PostgreSQLデータベースに対するLC_CTYPEの影響は何ですか?


25

そのため、PostgreSQLを搭載したDebianサーバーはほとんどありません。歴史的に、これらのサーバーとPostgreSQLはLatin 9文字セットでローカライズされていましたが、当時は問題ありませんでした。現在、ポーランド語、ギリシャ語、中国語などを処理する必要があるため、それを変更することは大きな問題になります。

UTF8データベースを作成しようとすると、次のメッセージが表示されました。

エラー:UTF8のエンコードはロケールfr_FRに一致しません詳細:選択したLC_CTYPE設定にはLATIN9のエンコードが必要です。

私は昔のパルグーグルでいくつかのテーマについて調査しましたが、Debianの更新LANG、正しい文字セットでのPostgreSQLの再コンパイル、すべてのLC_システム変数およびその他のあいまいなソリューションの編集など、複雑すぎる手順しか見つかりませんでした。とりあえず、この問題はさておきましょう。

最近、それは再び戻ってきました。ギリシャ人は物を望み、ラテン語9は望んでいません。そして、私がこの問題を再び検討している間に、ある同僚が私のところに来て、「ええ、簡単だ、見て」と言いました。

彼は何も編集せず、手品をしませんでした。彼はこのSQLクエリを作成しました。

CREATE DATABASE my_utf8_db
  WITH ENCODING='UTF8'
       OWNER=admin
       TEMPLATE=template0
       LC_COLLATE='C'
       LC_CTYPE='C'
       CONNECTION LIMIT=-1
       TABLESPACE=pg_default;

そして、それはうまくいきました。

私は実際には知りLC_CTYPE='C'ませんでしたが、これがGoogleの最初のソリューションやStack Overflowでも使用されていないことに驚きました。私は周りを見回しましたが、PostgreSQLのドキュメントに言及しているだけです。

LC_CTYPEがCまたはPOSIXの場合、任意の文字セットが許可されますが、LC_CTYPEの他の設定では、正しく機能する文字セットは1つだけです。LC_CTYPE設定はinitdbによって凍結されるため、クラスターの異なるデータベースで異なるエンコードを使用するための明らかな柔軟性は、CまたはPOSIXロケールを選択する場合を除いて、実際よりも理論的です(したがって、実際のロケール認識を無効にします)。

だから、これはあまりにも簡単で完璧すぎると思いました。マイナス面は何ですか?そして、私はまだ答えを見つけるのに苦労しています。だからここに投稿します:

tl; dr:特定のローカライズで使用LC_CTYPE='C'することのマイナス面は何ですか?そうするのは悪いですか?私は何を壊すことを期待すべきですか?

回答:


25

特定のローカライズでLC_CTYPE = 'C'を使用することのマイナス面は何ですか

ドキュメントでは、ロケールとロケールサポートの SQL機能との関係について言及しています。

ロケール設定は、次のSQL機能に影響します。

  • ORDER BYまたはテキストデータの標準比較演算子を使用したクエリの並べ替え順序

  • upper、lower、およびinitcap関数

  • パターンマッチング演算子(LIKE、SIMILAR TO、およびPOSIXスタイルの正規表現); ロケールは、大文字と小文字を区別しないマッチングと、文字クラスの正規表現による文字の分類の両方に影響します

  • to_charファミリーの関数

  • LIKE句でインデックスを使用する機能

最初の項目(ソート順)は約でLC_COLLATEあり、他の項目はすべて約であるようですLC_CTYPE

LC_COLLATE

LC_COLLATE文字列間の比較に影響します。実際には、最も目に見える効果はソート順です。LC_COLLATE='C'(またはPOSIX同義語)は、比較を駆動するのはバイト順であることをlanguage_REGION意味しますが、フォーム内のロケールは、文化的ルールが比較を駆動することを意味します。

UTF-8データベース内から実行されるフランス語名の例:

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris'))
 AS l(firstname)
order by firstname collate "fr_FR";

結果:

 ファーストネーム 
-----------
 演劇
 ベレニツェ
 バーナード
 ボリス

béatrice前に来るboris、それは非アクセントになったかのようにアクセント付きEはOに対して比較しているため、。それは文化的なルールです。

これは、Cロケールで起こることとは異なります。

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris')) 
 AS l(firstname)
order by firstname collate "C";

結果:

 ファーストネーム 
-----------
 バーナード
 ボリス
 演劇
 ベレニツェ

これで、Eがアクセント付きの名前がリストの最後にプッシュされます。éUTF-8 のバイト表現は16進数でC3 A9あり、oそのため6fです。c3より大きい6fの下のでC、ロケール'béatrice' > 'boris'

アクセントだけではありません。ハイフネーション、句読点、およびのような奇妙な文字を使用したより複雑なルールがありœます。奇妙な文化的ルールは、すべてのロケールで期待されています。

これで、比較する文字列が異なる言語を混在させる場合、firstname他のすべての世界の人々のための列があるとき、とにかく、特定のロケールが支配するべきではないかもしれません、異なる言語の異なるアルファベットは互いに並べ替えられます。

この場合Cは合理的な選択であり、純粋なバイト比較に勝るものはないため、高速であるという利点があります。

LC_CTYPE

持つLC_CTYPE「C」にセットすると、のようなC言語の関数ことを意味isupper(c)かはtolower(c)唯一の(、ユニコードでコードポイントから0x7Fまでです)US-ASCIIの範囲の文字のために期待される結果を与えます。

や などのSQL関数はupper()、これらのlibc関数の上にPostgresで実装されているため、文字列に非US-ASCII文字があるとすぐにこの影響を受けます。lower()initcap

例:

test=> show lc_ctype;
  lc_ctype   
-------------
 fr_FR.UTF-8
(1 row)

-- Good result
test=> select initcap('élysée');
 initcap 
---------
 Élysée
(1 row)

-- Wrong result
-- collate "C" is the same as if the db has been created with lc_ctype='C'
test=> select initcap('élysée' collate "C");
 initcap 
---------
 éLyséE
(1 row)

以下のためにC、ロケール、éカテゴライズ文字として扱われます。

同様に、正規表現でも間違った結果が得られます。

test=> select 'élysée' ~ '^\w+$';
 ?column? 
----------
 t
(1 row)

test=> select 'élysée' COLLATE "C" ~ '^\w+$';
 ?column? 
----------
 f
(1 row)

したがって、私がそれを正しく理解すると、UTF-8サーバーを作成した場合でも順序の問題が発生しますか?システムLC_CTYPEをUTF-8に設定したり、PostgreSQLをUTF-8でコンパイルすると、指摘したのと同じ比較の問題が発生すると思います。
グレゴワールD.

これを拡張するために、クエリで照合を強制して、ローカルで比較が正しくなるようにすることは可能でしょうか?
グレゴワールD.

はい、個別の文字列比較には、この回答でのcollate "C"後にあるように、独自の照合規則を埋め込むことができorder byます。アプリケーションがそれを必要とするかどうか、どこでそれを必要とするかを決定するのはあなた次第です。世の中にあるほとんどのアプリケーションはあまり気にしません。
ダニエルヴェリテ

1
また、個々の列にはCOLLATEデータベースとは異なる指定子が含まれている場合があることに注意してください。
ダニエルヴェリテ

2
この答えは、LC_CTYPEではなく、LC_COLLATEに対するものです。LC_CTYPEは、文字等、数字、文字、空白、句読点であるかどうかを判断するために使用される
jjanes

10

照合順序を使用した並べ替えに関するダニエルの受け入れられた回答を参照して、MacでPostgreSQLを実行している場合、オペレーティングシステムレベルでの照合順序の設定が不適切なため、優先照合順序が期待どおりに機能しない可能性があることに注意してください。この問題の詳細については、こちらをご覧ください。

http://www.postgresql.org/message-id/4B4E845F.80906@postnewspapers.com.au

これは、特にPostgreSQL固有の問題ではなく、Macの照合設定のデフォルト設定に関する問題です。私の現在のシステムはOS X El Capitanバージョン10.11でPostgreSQL 9.3を実行しており、この問題に悩まされています。「fr_FR」または「en_US」照合を使用するかどうかに関係なく、システムは同じクエリ結果を返します。例えば:

「fr_FR」照合の使用:

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris'))
AS l(firstname)
order by firstname collate "fr_FR";

results:
==============
bernard
boris
béatrice
bérénice

「en_US」照合の使用:

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris'))
AS l(firstname)
order by firstname collate "en_US";

results:
==============
bernard
boris
béatrice
bérénice

私のシステムでは、照合設定(オペレーティングシステムレベル)は、diffを実行することでシェルで示されているように、「fr_FR」と「en_US」で同じです。

cd /usr/share/locale
diff fr_FR.UTF-8/LC_COLLATE en_US.UTF-8/LC_COLLATE

この追加情報が、この問題に苦しんでいるMacでPostgreSQLを使用している人に役立つことを願っています。


最新のMacでどのように機能させることができますか。Macで機能させるために何か作業をしましたか?
ディネシュクマール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.