Как выбрать сопоставление для международной базы данных?

22

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

SELECT a < b COLLATE "de_DE" FROM test1;

Предполагая, что это правильный способ работы с международными данными, какова наилучшая сортировка для самой базы данных? Документация PostgreSQL гласит :

Оба сопоставления C и POSIX задают «традиционное поведение C», при котором только буквы ASCII от «A» до «Z» обрабатываются как буквы, а сортировка выполняется строго по значениям байтов кода символа.

Я думаю, что это лучший выбор в этом случае, или я ошибаюсь?

(Бонусный вопрос: слишком медленно выбирается сортировка в самом запросе?).

Tae
источник
2
Самая большая болевая точка, с которой вы столкнетесь, состоит в том, что в многоязычной БД вам нужно много индексов, поскольку индексы для разборчивого текста зависят от параметров сортировки. Если вы склонны искать только в частичном сопоставлении / языке, вы можете использовать частичные индексы, чтобы помочь контролировать размер индекса.
Крейг Рингер
2
При цитировании источника добавьте ссылку.
Эрвин Брандштеттер

Ответы:

27

CСверка является правильным выбором.

Все немного быстрее без локали. А так как никакое сопоставление не является правильным, создайте базу данных без сопоставления, то есть с C.

Это может быть боль, чтобы обеспечить сопоставление для многих операций. Однако не должно быть заметной разницы в скорости между сопоставлением по умолчанию и специальным сопоставлением. Ведь это просто несортированные данные, и при сортировке применяются правила сортировки.

Имейте в виду, что Postgres основывается на настройках локали, предоставляемых базовой ОС, поэтому вам нужно генерировать локали для каждой используемой локали. Больше в соответствующем ответе на SO здесь и здесь .

Однако, как @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

Я предлагаю вам выбрать параметры сортировки, которые обеспечивают порядок Юникода по умолчанию. Таким образом, вы получите нормальные результаты, даже если вы не переопределите параметры сортировки в каждом запросе. К сожалению, большинство (все?) Операционных систем не предоставляют локаль, которая просто называется «Юникод по умолчанию» или что-то в этом роде, поэтому вам придется угадывать и / или исследовать хороший выбор. Например, в Linux / glibc локали de_DE.utf8 или en_US.utf8 просто проходят через поведение по умолчанию, поэтому оба варианта являются хорошим выбором.

Я не думаю, что использование языка Си - хорошая идея, потому что тогда поведение вашего приложения по умолчанию будет бесполезным. И вы можете не получить надлежащего поведения от операций преобразования регистра.

(Переопределение параметров сортировки в запросе не требует больших накладных расходов. Это просто операция анализа времени.)

Питер Айзентраут
источник
Вероятно, меньше боли, чтобы иметь вменяемый дефолт ..
Эрвин Брандштеттер
1
В настоящее время я использую es_CL.utf8 в тестовой базе данных, но благодаря вашему ответу я посмотрел немного больше и обнаружил, что utf8_unicode_ciэто путь .
Тэ
0

Мы используем postgres в док-контейнере, поэтому у нас всегда есть ICU и мы используем его und-x-icuпо умолчанию.

Это упоминается в главе 23.2.2.2.2. ICU сборники пост-документов упоминает:

und-x-icu (для «неопределенного»)
«корневая» сортировка ICU. Используйте это, чтобы получить разумный порядок сортировки, не зависящий от языка.

TmTron
источник