Comment choisir un classement pour une base de données internationale?

22

Je conçois une base de données qui stockera des données dans différentes langues (en utilisant UTF-8), donc je pense que la meilleure façon d'afficher les résultats de la requête est de les ordonner en fonction de la langue de l'utilisateur pendant la requête elle-même ( car il y en a plusieurs bonnes façons de le faire ), comme suit:

SELECT a < b COLLATE "de_DE" FROM test1;

En supposant que c'est la bonne façon de travailler avec des données internationales, quel est le meilleur classement pour la base de données elle-même? La documentation PostgreSQL dit :

Les classements C et POSIX spécifient tous deux un comportement "C traditionnel", dans lequel seules les lettres ASCII "A" à "Z" sont traitées comme des lettres, et le tri est strictement effectué par des valeurs d'octets de code de caractère.

Je pense que c'est le meilleur choix dans ce cas, ou je me trompe?

(Question bonus: est-il trop lent pour sélectionner le classement dans la requête elle-même?).

Tae
la source
2
Le plus gros problème que vous allez subir est que dans une base de données multilingue, vous avez besoin de beaucoup d'index, car les index sur le texte collatable sont spécifiques au classement. Si vous avez tendance à rechercher uniquement dans un classement / langage particulier, vous pouvez utiliser des index partiels pour aider à garder la taille de l'index sous contrôle, cependant.
Craig Ringer
2
Lorsque vous citez une source, ajoutez un lien.
Erwin Brandstetter

Réponses:

27

Le Cclassement est le bon choix.

Tout est un peu plus rapide sans locale. Et comme aucun classement n'est correct de toute façon, créez la base de données sans classement, c'est-à-dire avec C.

Il peut être difficile de devoir fournir un classement pour de nombreuses opérations. Cependant, il ne devrait pas y avoir de différence notable de vitesse entre le classement par défaut et un classement ad hoc. Après tout, ce ne sont que des données non triées et des règles de classement sont appliquées lors du tri.

Sachez que Postgres s'appuie sur les paramètres régionaux fournis par le système d'exploitation sous-jacent, vous devez donc générer des paramètres régionaux pour chaque paramètre régional à utiliser. Plus dans la réponse connexe sur SO ici et ici .

Cependant, comme @Craig l'a déjà mentionné , les index sont le goulot d'étranglement dans ce scénario. Le classement de l'index doit correspondre au classement de l'opérateur appliqué dans de nombreux cas qui impliquent des données de caractères.

Vous pouvez utiliser le COLLATEspécificateur dans les index pour produire des index correspondants. Les index partiels peuvent être le choix parfait si vous mélangez des données dans la même table.

Par exemple, une table avec des chaînes internationales:

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

Et vous êtes surtout intéressé par une langue à la fois:

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

Créez ensuite des index partiels comme:

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

Un pour chaque langue dont vous avez besoin.

En fait, l' héritage pourrait être une approche supérieure pour une table comme celle-ci. Ensuite, vous pouvez avoir un index simple sur chaque table héritée contenant uniquement des chaînes pour un seul paramètre régional. Vous devez bien sûr être à l'aise avec les règles spéciales pour les tables héritées.

Erwin Brandstetter
la source
1
Utilisez-vous les paramètres régionaux C (ou «non locaux» pour être précis) par défaut pour toute nouvelle base de données?
Jack Douglas
1
@JackDouglas: Non, je ne ferais cela que pour des cas particuliers. En règle générale, il est beaucoup plus pratique de travailler avec les paramètres régionaux généralement utilisés sur place.
Erwin Brandstetter
13

Je vous suggère de choisir un classement qui fournit la commande Unicode par défaut. De cette façon, vous obtenez des résultats raisonnables même si vous ne remplacez pas le classement dans chaque requête. Malheureusement, la plupart (tous?) Des systèmes d'exploitation ne fournissent pas de paramètres régionaux qui sont simplement appelés "Unicode par défaut" ou quelque chose comme ça, vous devrez donc deviner et / ou rechercher un bon choix. Par exemple, sur Linux / glibc, les paramètres régionaux de_DE.utf8 ou en_US.utf8 passent simplement par le comportement par défaut, donc les deux sont de bons choix.

Je ne pense pas que l'utilisation des paramètres régionaux C soit une bonne idée, car le comportement par défaut de votre application sera alors inutile. Et vous pourriez ne pas obtenir un comportement correct des opérations de conversion de cas.

(Remplacer le classement dans une requête n'a pas beaucoup de surcharge. C'est juste une opération d'analyse.)

Peter Eisentraut
la source
Probablement moins de douleur pour avoir un défaut sain d'esprit ..
Erwin Brandstetter
1
Actuellement, j'utilise es_CL.utf8 dans une base de données de test, mais grâce à votre réponse, j'ai regardé un peu plus et j'ai trouvé que c'était utf8_unicode_cila voie à suivre .
Tae
0

Nous utilisons postgres dans un conteneur docker, donc nous avons toujours ICU disponible et utilisons und-x-icupar défaut.

Ceci est mentionné au chapitre 23.2.2.2.2. Les classements ICU des postres docs mentionnent:

und-x-icu (pour «non défini») Collation
ICU «racine». Utilisez-le pour obtenir un ordre de tri indépendant de la langue.

TmTron
la source