Como escolher um agrupamento para banco de dados internacional?


22

Como estou projetando um banco de dados que armazena dados em diferentes idiomas (usando UTF-8), acho que a melhor maneira de exibir os resultados da consulta é ordená-los de acordo com o idioma do usuário durante a consulta ( porque há mais de um maneiras corretas de fazer isso ), da seguinte maneira:

SELECT a < b COLLATE "de_DE" FROM test1;

Supondo que essa seja a maneira correta de trabalhar com dados internacionais, qual é o melhor agrupamento para o próprio banco de dados? A documentação do PostgreSQL diz :

Os agrupamentos C e POSIX especificam o comportamento "tradicional C", no qual apenas as letras ASCII "A" a "Z" são tratadas como letras e a classificação é feita estritamente pelos valores de bytes do código de caracteres.

Eu acho que é a melhor escolha neste caso, ou estou errado?

(Pergunta bônus: é muito lento para selecionar o agrupamento na própria consulta?).


2
O maior ponto de dor que você sofrerá é que, em um banco de dados multilíngue, você precisa de muitos índices, pois os índices no texto colecionável são específicos do agrupamento. Se você tende a pesquisar apenas em um agrupamento / idioma particular, pode usar índices parciais para ajudar a manter o tamanho do índice sob controle.
Craig Ringer

2
Ao citar uma fonte, adicione um link.
Erwin Brandstetter

Respostas:


27

O Cagrupamento é a escolha certa.

Tudo é um pouco mais rápido sem local. E como nenhum agrupamento está correto, crie o banco de dados sem agrupamento, ou seja, com C.

Pode ser uma dor ter que fornecer um agrupamento para muitas operações. Porém, não deve haver uma diferença notável na velocidade entre o agrupamento padrão e um agrupamento ad-hoc. Afinal, são apenas dados não classificados e as regras de ordenação são aplicadas na classificação.

Esteja ciente de que o Postgres se baseia nas configurações de localidade fornecidas pelo sistema operacional subjacente; portanto, é necessário gerar localidades geradas para cada localidade a ser usada. Mais respostas relacionadas ao SO aqui e aqui .

No entanto, como o @Craig já mencionado , os índices são o gargalo nesse cenário. O agrupamento do índice deve corresponder ao agrupamento do operador aplicado em muitos casos que envolvem dados de caracteres.

Você pode usar o COLLATEespecificador em índices para produzir índices correspondentes. Índices parciais podem ser a escolha perfeita se você estiver misturando dados na mesma tabela.

Por exemplo, uma tabela com cadeias internacionais:

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

E você está interessado principalmente em um idioma por vez:

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

Em seguida, crie índices parciais como:

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

Um para cada idioma que você precisa.

Na verdade, a herança pode ser uma abordagem superior para uma tabela como esta. Em seguida, você pode ter um índice simples em cada tabela herdada contendo apenas cadeias de caracteres para um único código de idioma. Você precisa estar confortável com as regras especiais para tabelas herdadas, é claro.


1
Você usa a localidade C (ou 'não localidade' para ser mais preciso) por padrão para qualquer novo banco de dados?
Jack Douglas

1
@JackDouglas: Não, eu faria isso apenas em casos especiais. Normalmente, é muito mais prático trabalhar com o local geralmente usado no local.
Erwin Brandstetter

13

Sugiro que você escolha um agrupamento que forneça o pedido Unicode padrão. Dessa forma, você obtém resultados sensatos, mesmo que não substitua o agrupamento em cada consulta. Infelizmente, a maioria dos sistemas operacionais (todos?) Não fornece um código de idioma simplesmente denominado "Unicode padrão" ou algo parecido; portanto, você terá que adivinhar e / ou pesquisar uma boa opção. Por exemplo, no Linux / glibc, os códigos de idioma de_DE.utf8 ou en_US.utf8 simplesmente passam pelo comportamento padrão, portanto, essas duas são boas escolhas.

Não acho que usar o código de idioma C seja uma boa idéia, pois o comportamento padrão do seu aplicativo será inútil. E você pode não ter um comportamento adequado das operações de conversão de caso.

(Substituir o agrupamento em uma consulta não tem muita sobrecarga. É apenas uma operação de tempo de análise.)


Provavelmente menos dor de ter um padrão sã ..
Erwin Brandstetter

1
Atualmente, estou usando es_CL.utf8 em um banco de dados de teste, mas, graças à sua resposta, olhei um pouco mais e descobri que esse utf8_unicode_cié o caminho a percorrer .
Tae

0

Usamos o postgres em um contêiner de docker, portanto, sempre temos a UTI disponível e usamos und-x-icucomo padrão.

Isso é mencionado no capítulo 23.2.2.2.2. Os agrupamentos de UTI dos documentos de pós-menção mencionam:

und-x-icu (para "indefinido")
agrupamento "raiz" da UTI. Use isso para obter uma ordem de classificação independente de idioma razoável.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.