Bagaimana cara memilih collation untuk basis data internasional?

22

Saya merancang basis data yang akan menyimpan data dalam berbagai bahasa (menggunakan UTF-8), jadi saya pikir cara terbaik untuk menampilkan hasil kueri adalah memesannya sesuai dengan bahasa pengguna selama kueri itu sendiri ( karena ada lebih dari satu cara yang benar untuk melakukannya ), sebagai berikut:

SELECT a < b COLLATE "de_DE" FROM test1;

Dengan asumsi ini adalah cara yang benar untuk bekerja dengan data internasional, yang merupakan pemeriksaan terbaik untuk database itu sendiri? Dokumentasi PostgreSQL mengatakan :

Kolaborasi C dan POSIX keduanya menentukan perilaku "C tradisional", di mana hanya huruf ASCII "A" hingga "Z" yang diperlakukan sebagai huruf, dan pengurutan dilakukan secara ketat oleh nilai byte kode karakter.

Saya pikir ini adalah pilihan terbaik dalam kasus ini, atau apakah saya salah?

(Pertanyaan bonus: apakah terlalu lambat untuk memilih susunan dalam permintaan itu sendiri?).

Tae
sumber
2
Titik sakit terbesar yang akan Anda derita adalah bahwa dalam DB multi-bahasa Anda memerlukan banyak indeks, karena indeks pada teks yang dapat dikoleksi adalah spesifik-collation. Jika Anda cenderung mencari hanya dalam kolasi / bahasa partiular, Anda dapat menggunakan indeks parsial untuk membantu menjaga ukuran indeks tetap terkendali.
Craig Ringer
2
Saat mengutip sumber, tambahkan tautan.
Erwin Brandstetter

Jawaban:

27

The Cpemeriksaan adalah pilihan yang tepat.

Semuanya sedikit lebih cepat tanpa lokal. Dan karena tidak ada susunan yang benar, buat basis data tanpa susunan , artinya dengan C.

Mungkin menyusahkan harus menyediakan pemeriksaan untuk banyak operasi. Seharusnya tidak ada perbedaan yang mencolok dalam kecepatan antara susunan standar dan susunan ad-hoc. Lagi pula itu hanya data yang tidak disortir, dan aturan pemeriksaan diterapkan saat menyortir.

Ketahuilah bahwa Postgres dibuat berdasarkan pengaturan lokal yang disediakan oleh OS yang mendasarinya, jadi Anda perlu membuat lokal yang dihasilkan untuk setiap lokal yang akan digunakan. Lebih banyak jawaban terkait pada SO di sini dan di sini .

Namun, seperti @Craig sudah sebutkan , indeks adalah hambatan dalam skenario ini. Susunan indeks harus cocok dengan susunan operator yang diterapkan dalam banyak kasus yang melibatkan data karakter.

Anda dapat menggunakan COLLATEspecifier dalam indeks untuk menghasilkan indeks yang cocok. Indeks parsial mungkin merupakan pilihan yang sempurna jika Anda mencampur data dalam tabel yang sama.

Misalnya, tabel dengan string internasional:

CREATE TABLE string (
   string_id serial
  ,lang_id   int NOT NULL
  ,string    text NOT NULL
);

Dan Anda sebagian besar tertarik pada satu bahasa pada satu waktu:

SELECT *
FROM   string
WHERE  lang_id = 5  -- 5 being German / Germany here
AND    string > 'foo' COLLATE "de_DE"
ORDER  BY string COLLATE "de_DE";

Kemudian buat indeks parsial seperti:

CREATE INDEX string_string_lang_id_idx ON string (string COLLATE "de_DE")
WHERE lang_id = 5;

Satu untuk setiap bahasa yang Anda butuhkan.

Sebenarnya, pewarisan mungkin merupakan pendekatan yang unggul untuk tabel seperti ini. Kemudian Anda dapat memiliki indeks biasa pada setiap tabel yang diwarisi yang hanya berisi string untuk satu lokal. Anda harus merasa nyaman dengan aturan khusus untuk tabel yang diwarisi, tentu saja.

Erwin Brandstetter
sumber
1
Apakah Anda menggunakan C locale (atau 'non locale' secara tepat) secara default untuk setiap basis data baru?
Jack Douglas
1
@ JackDouglas: Tidak, saya hanya akan melakukan itu untuk kasus khusus. Biasanya jauh lebih praktis untuk bekerja dengan lokal yang umum digunakan di tempat itu.
Erwin Brandstetter
13

Saya sarankan Anda memilih collation yang menyediakan pemesanan Unicode default. Dengan begitu, Anda mendapatkan hasil yang waras meskipun Anda tidak menimpa pemeriksaan di setiap kueri. Sayangnya, sebagian besar (semua?) Sistem operasi tidak menyediakan lokal yang hanya bernama "Unicode default" atau sesuatu seperti itu, jadi Anda harus menebak dan / atau meneliti pilihan yang baik. Sebagai contoh, di Linux / glibc, lokal de_DE.utf8 atau en_US.utf8 cukup melewati perilaku default, jadi keduanya adalah pilihan yang baik.

Saya tidak berpikir menggunakan C locale adalah ide yang bagus, karena dengan itu perilaku default aplikasi Anda tidak akan berguna. Dan Anda mungkin tidak mendapatkan perilaku yang tepat dari operasi konversi kasus.

(Mengganti susunan dalam kueri tidak memiliki banyak overhead. Ini hanya operasi parse-waktu.)

Peter Eisentraut
sumber
Mungkin lebih sedikit rasa sakit untuk memiliki standar waras ..
Erwin Brandstetter
1
Saat ini saya menggunakan es_CL.utf8 dalam database pengujian, tetapi berkat jawaban Anda, saya melihat sedikit lebih banyak dan menemukan bahwa utf8_unicode_ciitulah cara yang harus dilakukan .
Tae
0

Kami menggunakan postgres dalam wadah buruh pelabuhan, sehingga kami selalu memiliki ICU yang tersedia dan digunakan und-x-icusebagai default.

Ini disebutkan dalam bab 23.2.2.2.2. Kumpulan ICU dari dokumen-dokumen pos menyebutkan:

und-x-icu (untuk "undefined")
ICU "root" collation. Gunakan ini untuk mendapatkan urutan bahasa-agnostik yang masuk akal.

TmTron
sumber