sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQL10でのICUサポートとのより堅牢な照合

    この記事では、PostgreSQLバージョン10で取り組んできたPostgreSQLでのICUサポートを紹介したいと思います。

    並べ替え

    並べ替えは、データベースシステムの重要な機能です。まず、ユーザーは通常、データが並べ替えられていることを確認したいと考えています。複数の行を含み、エンドユーザーが使用することを目的としたクエリ結果は、ユーザーエクスペリエンスを向上させるために、並べ替える必要があります。第2に、データベースシステムの内部機能の多くは、データの並べ替えまたは並べ替えられたデータを使用できるかどうかに依存します。 Bツリーインデックスは明らかな例です。 BRINインデックスには順序に関する知識があります。範囲分割では、値を比較する必要があります。マージ結合は、ソートされた入力に依存します。これらのさまざまな手法に共通する考え方は、大まかに言えば、データを並べ替えて、探しているものがわかっている場合、データを見つける必要のある場所をすばやく見つけることができるということです。

    並べ替えには2つの重要な側面があります。 1つはソートアルゴリズムです。これはコンピュータサイエンスの標準的なトピックであり、さまざまな並べ替えアルゴリズムと方法を改良するために、何年にもわたってPostgreSQLに多くの作業が費やされてきましたが、それについては説明しません。もう1つは、物事の順序を決定することです。これを照合と呼びます。多くの場合、その選択は明らかです。 1は2の前に来ます。FALSEはTRUEの前に来ます…まあ、誰かが勝手にそれを決めました。通常、AはBの前に来ます。しかし、自然言語のテキストになると、物事は面白くなります。テキストを並べ替えるにはさまざまな方法があり、テキスト文字列を照合する実際の方法は、見た目よりも複雑です。言語が異なれば、ソート順も異なりますが、言語内であっても、アプリケーションごとにバリエーションがあります。また、空白、句読点、大文字と小文字の違い、発音区別符号などをどうするかなど、気になる詳細があります。これに関する詳細については、Unicode照合アルゴリズムを調べてください。

    ICU機能がコミットされる前は、このすべての機能はオペレーティングシステムのCライブラリによって促進されていました。 PostgreSQLは基本的に、文字列をstrcmp()に渡すだけです。 、strcoll() 、などと結果を処理します。さまざまなオペレーティングシステムのCライブラリは、上記のさまざまな照合バリアントとニュアンスをさまざまなレベルの機能と品質に実装しているため、PostgreSQLはオペレーティングシステムが実行できることを実行できます。

    照合の変更

    オペレーティングシステムが提供する照合を変更する必要がある場合、問題が発生します。なぜ彼らはそれをしたいのですか?以前の照合が間違っていたため、修正する必要があった可能性があります。たぶん、言語の新しい標準が公開され、そのために照合が更新される予定です。パフォーマンス上の理由から、または追加機能を実装する必要があったために、照合および文字列データの内部表現が変更された可能性があります。多くのプログラムでは、これは問題ではありません。違いに気付いた場合は、わずかに異なる順序の出力が表示される場合があります。ただし、データベースシステムの場合、これは大きな問題です。上記のように、PostgreSQLはソートされたデータをインデックスやその他の場所に格納し、ソート順が正しいかどうかに依存します。並べ替え順序が正しくない場合、インデックスルックアップで実際に存在するデータが見つからない可能性があります。または、インデックスへの書き込みは別の場所に書き込みます。または、データが間違ったパーティションに書き込まれたり、間違ったパーティションから読み取られたりします。これにより、データが検索された場所にないため、誤ってデータが重複したり、データが失われたりする可能性があります。つまり、データの破損や(明らかな)データの損失につながる可能性があります。

    残念ながら、これまでのところ、私たちにできることはあまりありませんでした。オペレーティングシステムは、おそらくCライブラリパッケージへのアップグレードの一環として、必要に応じて照合を更新します。合理的な方法で、またはおそらく更新パッケージを詳細に調べることによって、これを知る方法はありません。それでも、使用していないロケールの照合が変更されていることに気付いたため、Cライブラリの重要な更新を拒否しますか?とても不快な状況でした。

    ICUに入る

    では、ICUはどこからやってくるのでしょうか? ICU(International Components for Unicode)は、照合を含む国際化およびローカリゼーション機能を提供するライブラリです。したがって、その点では、標準Cライブラリの機能を使用する代わりになります。良い点は、ICUが照合の安定性についていくつかの保証を明示的に提供していることです:

    • マイナーリリースアップデートの一部として、照合が互換性のない方法で変更されることはありません。
    • 照合には検査可能なバージョンがあり、照合が互換性のない方法で変更されると、バージョンが変更されます。

    PostgreSQLのユーザーにとって、これは実際には次のことを意味します:

    • 定期的なオペレーティングシステムパッケージの更新は、並べ替えられたデータの有効性を妨げることはありません。 postgres以降 バイナリは、libicuの特定のメジャーバージョンにリンクされています 、定期的なオペレーティングシステムパッケージのアップグレードは、postgresで終了しません libicuの新しいメジャーバージョンにリンクされている 、a)PostgreSQLパッケージを更新しない場合、またはb)PostgreSQLパッケージが以前と同じメジャーバージョンのICUにリンクされている場合に限ります。パッケージャーはこれを適切に維持するように注意する必要がありますが、実際にはそれほど問題にはならないはずです。
    • メジャーパッケージとオペレーティングシステムのアップグレードによって照合のバージョンが変更された場合、それを検出してユーザーに警告する方法があります。現在、問題を修正するためのいくつかのガイドラインとツールを警告して提供していますが、将来的にはこれをさらに改良して自動化する可能性があります。

    (これをパッケージャーに対してより明確にするために:オペレーティングシステムの安定したブランチでは、特定のPostgreSQLパッケージセットがリンクされているメジャーICUバージョンを変更しないでください。)

    ICUの使用

    これを使用できるようにするには、PostgreSQLをICUサポートを使用して明示的に構築する必要があります。ソースからビルドする場合は、./configure --with-icuを使用します 他の望ましいオプションと一緒に。ほとんどの主要なバイナリパッケージもデフォルトでこれを提供することを期待しています。これが行われると、ICUベースの照合が、以前のリリースで提供されていたlibcベースの照合とともに提供されます。 (したがって、ICUサポートを使用してビルドしてもlibc照合サポートは削除されません。2つは一緒に存在します。)ICUベースの照合とlibcベースの照合を選択する方法の詳細については、ドキュメントを確認してください。たとえば、以前に指定した場合

    CREATE TABLE ... (... x text COLLATE "en_US" ...)

    あなたは今やるかもしれません

    CREATE TABLE ... (... x text COLLATE "en-x-icu" ...)

    これにより、アップグレードに関してデータベースの将来性が向上することを除けば、以前とほぼ同じユーザーに表示される動作が得られるはずです。 (Linux / glibcでは、ソート順はほとんど同じですが、細部に若干の違いがある場合があります。ただし、macOSやmacOSなどのCライブラリがUnicode照合をまったくサポートしていないオペレーティングシステムを使用している場合FreeBSDの古いバージョンの場合、これは大きな変更になります—より良い方向に。)

    現在、ICUサポートは、明示的に指定された照合でのみ使用できます。データベースのデフォルトの照合は、引き続きCライブラリによって提供されます。これに対処することは将来のプロジェクトです。

    このようなデータベースをpg_upgradeでアップグレードする場合 たとえば、使用している照合の照合バージョンを変更したICUの新しいメジャーバージョンにリンクされている新しいPostgreSQLインストールの場合、警告が表示され、たとえば、に依存するインデックスを修正する必要があります。照合。この手順はドキュメントにもあります。

    省略されたキー

    したがって、この変更により、データベースシステムの長期的な堅牢性に非常に重要な改善がもたらされます。しかし、ICUは、他の分野のシステムCライブラリよりも改善されています。

    たとえば、PostgreSQL Bツリーは、パフォーマンスとストレージを向上させるために、いわゆる省略キーを格納できます。テキスト文字列データ型の場合、標準Cライブラリでは、strxfrm()を使用してこれらの省略キーを計算します。 働き。ただし、多くのCライブラリには、このアプローチを信頼できないものにするさまざまなバグや誤動作があることがわかりました。そのため、現在、文字列データ型では省略キーの最適化が無効になっています。 ICUを使用すると、同等のAPI呼び出しを使用して、信頼性が高く安定した方法で短縮キーを計算できます。したがって、この移動によってパフォーマンスが向上する可能性もあります。

    その他の照合

    堅牢性とパフォーマンスのこれらの内部改善とは別に、いくつかの新しいユーザー向け機能もあります。

    一部の言語では、実際には複数のソート順が関連している場合があります。 (これで始めることができます。)1つの例は、ドイツ語の場合、ほとんどの目的で使用される標準の並べ替え順序と、名前のリストに使用される「電話帳」の並べ替え順序があることです。標準Cライブラリは、これらのバリアントの1つ(おそらく最初のバリアント)のみを提供します。ただし、たとえば製品名と顧客名の両方を適切に並べ替えるアプリケーションを作成する場合は、両方を使用できる必要があります。

    たとえば、ドイツ語版ウィキペディアの例をPostgreSQLで再現できるようになりました:

    CREATE TABLE names (name text);
    
    INSERT INTO names
        VALUES ('Göbel'), ('Goethe'), ('Goldmann'), ('Göthe'), ('Götz');
    
    => SELECT name FROM names ORDER BY name COLLATE "de-u-co-standard-x-icu";
       name
    ----------
     Göbel
     Goethe
     Goldmann
     Göthe
     Götz
    
    => SELECT name FROM names ORDER BY name COLLATE "de-u-co-phonebk-x-icu";
       name
    ----------
     Göbel
     Goethe
     Göthe
     Götz
     Goldmann
    
    => SELECT name FROM names ORDER BY name COLLATE "de-AT-u-co-phonebk-x-icu";
       name
    ----------
     Goethe
     Goldmann
     Göbel
     Göthe
     Götz
    

    (glibcでは、COLLATE "de_DE" およびCOLLATE "de_AT" 確かに最初の注文を返します。)

    複数の機能を組み合わせる興味深い方法の1つは、ドメインを使用して、上記の製品名と顧客名の違いをモデル化することです。

    CREATE DOMAIN product_name AS text COLLATE "de-u-co-standard-x-icu";
    CREATE DOMAIN person_name AS text COLLATE "de-u-co-phonebk-x-icu";
    

    (これは単なる例です。もちろん、これらのCOLLATEを添付することもできます。 列定義への句を直接、またはクエリで使用します。)

    さらに多くの照合

    最後に、これは明らかに世界が待ち望んでいたことであり、絵文字を適切に並べ替える方法があります。これは、すべての猫の顔が正しい順序になっていることを確認するために不可欠です。比較

    =# SELECT chr(x) FROM generate_series(x'1F634'::int, x'1F644'::int) AS _(x)
           ORDER BY chr(x) COLLATE "und-x-icu";
     chr
    -----
     😴
     😵
     😶
     😷
     😸
     😹
     😺
     😻
     😼
     😽
     😾
     😿
     🙀
     🙁
     🙂
     🙃
     🙄
    

    =# CREATE COLLATION "und-u-co-emoji-x-icu" (provider = icu, locale = 'und-u-co-emoji');
    =# SELECT chr(x) FROM generate_series(x'1F634'::int, x'1F644'::int) AS _(x)
           ORDER BY chr(x) COLLATE "und-u-co-emoji-x-icu";
     chr
    -----
     🙂
     🙃
     😶
     🙄
     😴
     😷
     😵
     🙁
     😺
     😸
     😹
     😻
     😼
     😽
     🙀
     😿
     😾
    

    はい、実際にはこれに関する基準があります。

    今後の予定

    これは始まりにすぎない。 ICUは、PostgreSQLを通じてまだ公開していない、この分野の多くの機能を提供します。大文字と小文字を区別しない並べ替え、アクセントを区別しない並べ替え、および照合を完全にカスタマイズするためのオプションがあります。将来のPostgreSQLリリースでそれらを探してください。


    1. すべてのユーザーテーブルにクラスター化インデックスが必要ですか?

    2. PostgreSQLで(タイムゾーンなしで)現在の日付と時刻を取得する方法

    3. GROUPBY式のヘルプではないOracleSQLGROUP BY

    4. SQL Server(T-SQL)で文字列の正しい部分を取得する