Entre utf8_general_ci
et utf8_unicode_ci
, existe-t-il des différences en termes de performances?
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.
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()
utf8_general_ci
: 9 957 msutf8_unicode_ci
: 10,271 msDans ce repère, utiliser utf8_unicode_ci
est plus lent que utf8_general_ci
de 3,2%.
benchmark_select_like()
utf8_general_ci
: 11 441 msutf8_unicode_ci
: 12 811 msDans ce repère, utiliser utf8_unicode_ci
est plus lent que utf8_general_ci
de 12%.
benchmark_order_by()
utf8_general_ci
: 11 944 msutf8_unicode_ci
: 12 887 msDans ce repère, utiliser utf8_unicode_ci
est plus lent que utf8_general_ci
de 7,9%.
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".
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.
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.
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.