web-dev-qa-db-fra.com

Quelle est la différence entre utf8_general_ci et utf8_unicode_ci?

Entre utf8_general_ci et utf8_unicode_ci, existe-t-il des différences en termes de performances?

972
KahWee Teng

Ces deux classements sont tous deux destinés au codage de caractères UTF-8. Les différences sont dans la façon dont le texte est trié et comparé.

Remarque: Depuis MySQL 5.5.3, vous devriez utiliser utf8mb4 plutôt que _utf8_. Ils font tous deux référence au codage UTF-8, mais l'ancien _utf8_ avait une limitation spécifique à MySQL empêchant l'utilisation de caractères numérotés au-dessus de 0xFFFD.

Principales différences

  • _utf8mb4_unicode_ci_ est basé sur les règles Unicode officielles pour le tri et la comparaison universels, qui trient avec précision dans un large éventail de langues.

  • _utf8mb4_general_ci_ est un ensemble simplifié de règles de tri qui vise à faire de son mieux tout en prenant de nombreux raccourcis conçus pour améliorer la vitesse. Il ne suit pas les règles Unicode et entraînera un tri ou une comparaison indésirable dans certaines situations, comme l'utilisation de langues ou de caractères particuliers.

    Sur les serveurs modernes, cette amélioration des performances sera quasiment négligeable. Il a été conçu à une époque où les serveurs ne représentaient qu'une infime partie des performances du processeur des ordinateurs actuels.

Remarque: il existe maintenant une version mise à jour de _utf8mb4_unicode_ci_ appelée _utf8mb4_0900_ai_ci_ - basée sur les modifications apportées à la version Unicode 9.0 et apparemment aussi plus rapide. Elle adopte un nouveau schéma de nommage dans lequel _0900_ est la version Unicode et ai signifie qu’il n’y a pas d’accent, comme le précédent _utf8mb4_unicode_ci_, les accents dans les lettres ne sont pas considérés comme significatifs.

Avantages de _utf8mb4_unicode_ci_ par rapport à _utf8mb4_general_ci_

_utf8mb4_unicode_ci_, qui utilise les règles Unicode pour le tri et la comparaison, utilise un algorithme assez complexe pour un tri correct dans une large gamme de langues et lors de l'utilisation d'un large éventail de caractères spéciaux. Ces règles doivent prendre en compte les conventions spécifiques à la langue. tout le monde ne classe pas ses caractères dans ce que nous appellerions "ordre alphabétique".

En ce qui concerne les langues latines (c'est-à-dire "européennes"), il n'y a pas beaucoup de différence entre le tri Unicode et le tri simplifié _utf8mb4_general_ci_ dans MySQL, mais il existe encore quelques différences:

  • Par exemple, le classement Unicode trie "ß" comme "ss" et "Œ" comme "OE" comme le voudraient normalement les utilisateurs de ces caractères, alors que _utf8mb4_general_ci_ les trie sous forme de caractères uniques (vraisemblablement comme "s" et "e" respectivement).

  • Certains caractères Unicode sont définis comme étant ignorables, ce qui signifie qu'ils ne doivent pas être pris en compte dans l'ordre de tri et que la comparaison doit passer au caractère suivant. _utf8mb4_unicode_ci_ les gère correctement.

Dans les langues non latines, telles que les langues asiatiques ou avec des alphabets différents, il peut y avoir beaucoup de more différences entre le tri Unicode et le tri simplifié _utf8mb4_general_ci_. La pertinence de _utf8mb4_general_ci_ dépendra beaucoup de la langue utilisée. Pour certaines langues, ce sera assez insuffisant.

Que devriez-vous utiliser?

Il n’ya presque certainement aucune raison d’utiliser _utf8mb4_general_ci_, car nous avons laissé le point où la vitesse du processeur est suffisamment basse pour que la différence de performances soit importante. Votre base de données sera presque certainement limitée par d’autres goulots d’étranglement.

Dans le passé, certaines personnes recommandaient d’utiliser _utf8mb4_general_ci_ sauf lorsque le tri précis était suffisamment important pour justifier le coût en performances. Aujourd'hui, ce coût de performance a pratiquement disparu et les développeurs traitent l'internationalisation avec plus de sérieux.

On peut faire valoir que si la rapidité est plus importante pour vous que la précision, vous pouvez également ne faire aucun tri. Il est trivial de rendre un algorithme plus rapide si vous n'avez pas besoin qu'il soit précis. Donc, _utf8mb4_general_ci_ est un compromis qui n’est probablement pas nécessaire pour des raisons de rapidité ni pour des raisons de précision.

Une autre chose que je voudrais ajouter est que même si votre application ne prend en charge que la langue anglaise, elle devra peut-être traiter les noms des personnes, qui peuvent souvent contenir des caractères utilisés dans d'autres langues dans lesquelles il est tout aussi important de trier correctement. . L'utilisation des règles Unicode pour tout contribue à rassurer que les très intelligents employés d'Unicode ont travaillé très fort pour que le tri fonctionne correctement.

Que signifient les parties

Tout d'abord, ci est pour insensible à la casse == le tri et la comparaison. Cela signifie que cela convient aux données textuelles et que la casse n'est pas importante. Les autres types de classement sont cs (sensible à la casse) pour les données textuelles où la casse est importante, et bin, pour lequel le codage doit correspondre, bit à bit, ce qui convient aux champs qui sont données binaires réellement codées (y compris, par exemple, Base64). Le tri sensible à la casse entraîne des résultats étranges et une comparaison sensible à la casse peut entraîner des valeurs en double qui ne diffèrent que par des majuscules. Ainsi, les collations sensibles à la casse perdent en popularité pour les données textuelles. Si la casse est significative, une ponctuation ignorable et ainsi de suite est probablement aussi important, et un classement binaire pourrait être plus approprié.

Ensuite, unicode ou general fait référence aux règles de tri et de comparaison spécifiques, en particulier à la manière dont le texte est normalisé ou comparé. Il existe de nombreux ensembles de règles différents pour le codage de caractères utf8mb4, unicode et general étant deux systèmes qui tentent de fonctionner correctement dans toutes les langues possibles au lieu d'une langue spécifique. Les différences entre ces deux ensembles de règles font l’objet de cette réponse. Notez que les nouveaux ensembles de règles incluent _0900_ en référence à Unicode 9.0 et _unicode_520_ en référence à Unicode 5.2.

Enfin, _utf8mb4_ est bien sûr le codage de caractères utilisé en interne. Dans cette réponse, je parle uniquement des encodages basés sur Unicode.

1477
thomasrutter

Je voulais savoir quelle est la différence de performances entre utf8_general_ci et utf8_unicode_ci, mais je n’ai trouvé aucun repère répertorié sur Internet, j’ai donc décidé de le créer moi-même.

J'ai créé un tableau très simple avec 500 000 lignes:

CREATE TABLE test(
  ID INT(11) DEFAULT NULL,
  Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;

Ensuite, je l'ai rempli avec des données aléatoires en exécutant cette procédure stockée:

CREATE PROCEDURE randomizer()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE random CHAR(20) ;
  theloop: loop
    SET random = CONV(FLOOR(Rand() * 99999999999999), 20, 36);
    INSERT INTO test VALUES (i+1, random);
    SET i=i+1;
    IF i = 500000 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END

Ensuite, j'ai créé les procédures stockées suivantes pour évaluer simplement SELECT, SELECT avec LIKE et trier (SELECT avec ORDER BY):

CREATE PROCEDURE benchmark_simple_select()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE Description = 'test' COLLATE utf8_general_ci;
    SET i = i + 1;
    IF i = 30 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

CREATE PROCEDURE benchmark_select_like()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE Description LIKE '%test' COLLATE utf8_general_ci;
    SET i = i + 1;
    IF i = 30 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

CREATE PROCEDURE benchmark_order_by()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE ID > FLOOR(1 + Rand() * (400000 - 1))
    ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
    SET i = i + 1;
    IF i = 10 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

Dans les procédures stockées situées au-dessus de utf8_general_ci, le classement est utilisé, mais bien sûr, lors des tests, j'ai utilisé à la fois utf8_general_ci et utf8_unicode_ci.

J'ai appelé chaque procédure stockée 5 fois pour chaque classement (5 fois pour utf8_general_ci et 5 fois pour utf8_unicode_ci), puis j'ai calculé les valeurs moyennes.

Mes résultats sont:

benchmark_simple_select()

  • avec utf8_general_ci: 9 957 ms
  • avec utf8_unicode_ci: 10,271 ms

Dans ce repère, utiliser utf8_unicode_ci est plus lent que utf8_general_ci de 3,2%.

benchmark_select_like()

  • avec utf8_general_ci: 11 441 ms
  • avec utf8_unicode_ci: 12 811 ms

Dans ce repère, utiliser utf8_unicode_ci est plus lent que utf8_general_ci de 12%.

benchmark_order_by()

  • avec utf8_general_ci: 11 944 ms
  • avec utf8_unicode_ci: 12 887 ms

Dans ce repère, utiliser utf8_unicode_ci est plus lent que utf8_general_ci de 7,9%.

149
nightcoder

Ce post le décrit très bien.

En bref: utf8_unicode_ci utilise l'algorithme de classement Unicode tel que défini dans les normes Unicode, tandis que utf8_general_ci est un ordre de tri plus simple qui donne des résultats de tri "moins précis".

36
Michael Madsen

Voir le manuel mysql, Jeux de caractères Unicode section:

Pour tout jeu de caractères Unicode, les opérations effectuées à l'aide du classement _general_ci sont plus rapides que celles du classement _unicode_ci. Par exemple, les comparaisons pour le classement utf8_general_ci sont plus rapides, mais légèrement moins correctes que les comparaisons pour utf8_unicode_ci. La raison en est que utf8_unicode_ci prend en charge les mappages tels que les extensions; c'est-à-dire lorsqu'un caractère se compare à des combinaisons d'autres caractères. Par exemple, en allemand et dans certaines autres langues, "ß" est égal à "ss". utf8_unicode_ci supporte également les contractions et les caractères ignorables. utf8_general_ci est un classement hérité qui ne prend pas en charge les extensions, les contractions ni les caractères ignorables. Il ne peut faire que des comparaisons individuelles entre les personnages.

Donc, pour résumer, utf_general_ci utilise un ensemble de comparaisons plus petit et moins correct (selon le standard) que utf_unicode_ci qui devrait implémenter le standard entier. Le jeu general_ci sera plus rapide car il y a moins de calculs à faire.

8
Dana the Sane

En mots brefs:

Si vous avez besoin d’un meilleur ordre de tri - utilisez utf8_unicode_ci (c’est la méthode recommandée),

mais si vous êtes vraiment intéressé par la performance, utilisez utf8_general_ci, mais sachez que c'est un peu dépassé.

Les différences en termes de performances sont très faibles.

5
simhumileco

Quelques détails (PL)

Comme nous pouvons le lire ici ( Peter Gulutzan ) il y a une différence dans le tri/la comparaison de la lettre polonaise "Ł" (L avec trait - html esc: Ł) (minuscule: "ł" - html esc: ł) - nous avons l'hypothèse suivante:

utf8_polish_ci      Ł greater than L and less than M
utf8_unicode_ci     Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci     Ł greater than Z

En polonais, la lettre Ł est après la lettre L et avant M. Aucun de ces codages n'est meilleur ou pire - cela dépend de vos besoins.

2
Kamil Kiełczewski