さまざまな言語でデータを格納するデータベース(UTF-8を使用)を設計しているので、クエリの結果を表示する最良の方法は、クエリ自体の実行中にユーザーの言語に従って順序付けすることです( 次のように、それを行うための複数の正しい方法があります ):
SELECT a < b COLLATE "de_DE" FROM test1;
これが国際データを処理する正しい方法であると仮定すると、データベース自体に最適な照合順序はどれですか。 PostgreSQLドキュメントによると :
CとPOSIXの照合順序はどちらも「従来のC」の動作を指定し、ASCII文字「A」から「Z」のみが文字として扱われ、文字コードのバイト値によって厳密にソートされます。 。
この場合、これが最良の選択だと思いますか、それとも間違っていますか?
(ボーナス質問:クエリ自体で照合順序を選択するには遅すぎるのですか?).
C
collation が正しい選択です。
ロケールがないと、すべてが少し速くなります。そして、いずれの照合も正しくないため、データベースを作成しますなし照合、つまりC
を使用します。
多くの操作で照合を提供しなければならないのは面倒なことかもしれません。ただし、デフォルトの照合とアドホック照合の速度に目立った違いはありません。結局のところ、それは単にソートされていないデータであり、ソート時には照合ルールが適用されます。
Postgresは基盤となるOSによって提供されるロケール設定に基づいて構築されるため、使用するロケールごとにロケールを生成する必要があることに注意してください。 SO here および here の関連する回答の詳細。
ただし、 @ Craigはすでに説明済み なので、indexesがこのシナリオのボトルネックになります。インデックスの照合は、文字データが関係する多くの場合、適用される演算子の照合と一致する必要があります。
インデックスでCOLLATE
指定子を使用して、一致するインデックスを作成できます。 部分インデックス は、同じテーブルにデータを混在させる場合に最適な選択肢です。
たとえば、国際文字列を含むテーブル:
CREATE TABLE string (
string_id serial
,lang_id int NOT NULL
,string text NOT NULL
);
そして、あなたは一度に1つの言語にほとんど興味があります:
SELECT *
FROM string
WHERE lang_id = 5 -- 5 being German / Germany here
AND string > 'foo' COLLATE "de_DE"
ORDER BY string COLLATE "de_DE";
次に、次のような部分インデックスを作成します。
CREATE INDEX string_string_lang_id_idx ON string (string COLLATE "de_DE")
WHERE lang_id = 5;
必要な言語ごとに1つ。
実際、 inheritance は、このようなテーブルの優れたアプローチかもしれません。次に、単一のロケールの文字列のみを含む継承された各テーブルにプレーンインデックスを設定できます。もちろん、継承されたテーブルの特別なルールに慣れる必要があります。
デフォルトのUnicode順序を提供する照合を選択することをお勧めします。これにより、各クエリで照合順序をオーバーライドしなくても、正しい結果が得られます。残念ながら、ほとんど(すべて?)のオペレーティングシステムは、単に「デフォルトのUnicode」などの名前のロケールを提供していないため、適切な選択肢を推測または調査する必要があります。たとえば、Linux/glibcでは、de_DE.utf8またはen_US.utf8ロケールはデフォルトの動作を通過するだけなので、どちらも適切な選択肢です。
アプリケーションのデフォルトの動作は役に立たなくなるため、Cロケールを使用することはお勧めしません。また、大文字小文字変換操作から適切な動作が得られない場合があります。
(クエリの照合順序をオーバーライドしても、オーバーヘッドはあまりありません。これは、解析時の操作にすぎません。)
Dockerコンテナーではpostgresを使用しているため、ICUが常に利用可能であり、und-x-icu
デフォルトとして。
これは 23.2.2.2.2。ICU collations の章で言及されています:
und-x-icu(「未定義」の場合)
ICU「ルート」照合。これを使用して、言語に依存しない合理的な並べ替え順序を取得します。