Як вибрати порівняння для міжнародної бази даних?


22

Я розробляю базу даних, яка буде зберігати дані різними мовами (використовуючи UTF-8), тому я вважаю, що найкращим способом відображення результатів запиту є впорядкування його відповідно до мови користувача під час самого запиту ( тому що їх існує більше ніж одна правильні способи зробити це ):

SELECT a < b COLLATE "de_DE" FROM test1;

Якщо припустити, що це правильний спосіб роботи з міжнародними даними, що є найкращим порівнянням для самої бази даних? Документація PostgreSQL говорить :

І зіставлення C і POSIX вказують "традиційну C" поведінку, в якій лише букви ASCII "А" через "Z" трактуються як літери, а сортування проводиться суворо за значеннями байтових кодів символів.

Я думаю, що це найкращий вибір у цьому випадку, чи я помиляюся?

(Бонусне запитання: чи занадто повільно вибирати порівняння у самому запиті?).


2
Найбільшою больовою точкою, з якою ви будете зазнавати, є те, що в багатомовній БД вам потрібно багато індексів, оскільки індекси для тексту, що розгортається, є специфічними для порівняння. Якщо ви схильні шукати лише в межах часткового зібрання / мови, ви можете використовувати часткові індекси, які допомагають тримати під контролем розмір індексу.
Крейг Рінгер

2
Цитуючи джерело, додайте посилання.
Erwin Brandstetter

Відповіді:


27

CЗвірка є правильним вибором.

Все трохи швидше без локалу. А оскільки жодне зіставлення так і не підходить, створіть базу даних без зіставлення, тобто з C.

Для багатьох операцій може бути болем, щоб забезпечити порівняння. Не повинно бути помітної різниці у швидкості між типовим порівнянням та тимчасовим порівнянням. Зрештою, це лише несортовані дані, а при сортуванні застосовуються правила зіставлення.

Майте на увазі, що Postgres ґрунтується на налаштуваннях локалі, що надаються базовою ОС, тому вам потрібно створити локалі для кожного використовуваного локалу. Детальніше у відповіді на ТАК тут і тут .

Однак, як @Craig вже згадував , індекси є вузьким місцем у цьому сценарії. Порівняння індексу має відповідати порівнянню застосованого оператора у багатьох випадках, що містять символьні дані.

Ви можете використовувати COLLATEспецифікатор в індексах для створення відповідних індексів. Часткові індекси можуть бути ідеальним вибором, якщо ви змішуєте дані в одній таблиці.

Наприклад, таблиця з міжнародними рядками:

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

І вас найбільше цікавить одна мова за один раз:

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
Чи використовуєте ви C-локаль (або "не локальний" для точності) за замовчуванням для будь-якої нової бази даних?
Джек Дуглас

1
@JackDouglas: Ні, я б робив це лише для особливих випадків. Зазвичай набагато практичніше працювати з загальноприйнятим місцевим місцем у цьому місці.
Ервін Брандстеттер

13

Я пропоную вам вибрати порівняння, яке забезпечує замовлення Unicode за замовчуванням. Таким чином, ви отримуєте здорові результати, навіть якщо ви не перекриєте порівняння в кожному запиті. На жаль, більшість (усіх?) Операційних систем не надають локаль, який просто називають "Unicode за замовчуванням" або щось подібне, тому вам доведеться здогадуватися та / або досліджувати хороший вибір. Наприклад, в Linux / glibc локалі de_DE.utf8 або en_US.utf8 просто проходять через поведінку за замовчуванням, тому обидва з них є хорошим вибором.

Я не думаю, що використання локальної мови C не є гарною ідеєю, тому що тоді поведінка програми за замовчуванням буде марною. І ви не можете отримати належну поведінку від операцій перетворення справ.

(Перезапис зіставлення в запиті не має великих витрат. Це просто час аналізу.)


Напевно, менше боліти мати здоровий дефолт ..
Ервін Брандштеттер

1
Наразі я використовую es_CL.utf8 у тестовій базі даних, але завдяки вашій відповіді я трохи більше подивився та виявив, що utf8_unicode_ciце шлях .
Tae

0

Ми використовуємо postgres в контейнері docker, тому у нас завжди є ICU в наявності та використовується und-x-icuза замовчуванням.

Про це йдеться у главі 23.2.2.2.2. ICU посилань на документи Postres згадує:

und-x-icu (для "невизначеного")
ICU "root" зіставлення. Використовуйте це для отримання розумного мовно-агностичного порядку сортування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.