Entre utf8_general_ci
et utf8_unicode_ci
, y a-t-il des différences de performances?
utf8[mb4]_unicode_ci
, vous aimerez peut- être utf8[mb4]_unicode_520_ci
encore plus.
utf8mb4_0900_ai_ci
.
Entre utf8_general_ci
et utf8_unicode_ci
, y a-t-il des différences de performances?
utf8[mb4]_unicode_ci
, vous aimerez peut- être utf8[mb4]_unicode_520_ci
encore plus.
utf8mb4_0900_ai_ci
.
Réponses:
Ces deux classements sont tous deux destinés au codage de caractères UTF-8. Les différences résident dans la manière dont le texte est trié et comparé.
Remarque: Dans MySQL, vous devez utiliser utf8mb4
plutôt que utf8
. Confusément, utf8
est une implémentation UTF-8 défectueuse des premières versions de MySQL qui ne reste que pour la compatibilité descendante. La version fixe a reçu le nom utf8mb4
.
Remarque: Les versions plus récentes de MySQL ont mis à jour les règles de tri Unicode, disponibles sous des noms tels que utf8mb4_0900_ai_ci
des règles équivalentes basées sur Unicode 9.0 - et sans _general
variante équivalente . Les personnes qui lisent ceci maintenant devraient probablement utiliser l'une de ces nouvelles collations au lieu de _unicode
ou _general
. Une grande partie de ce qui est écrit ci-dessous n'a plus grand intérêt si vous pouvez utiliser l'un des classements les plus récents à la place.
Différences clés
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 du mieux qu'il peut tout en prenant de nombreux raccourcis destinés à 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 lors de l'utilisation de langues ou de caractères particuliers.
Sur les serveurs modernes, cette amélioration des performances sera presque négligeable. Il a été conçu à une époque où les serveurs avaient une infime fraction des performances CPU des ordinateurs d'aujourd'hui.
Avantages de utf8mb4_unicode_ci
plusutf8mb4_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 un large éventail de langues et lors de l'utilisation d'un large éventail de caractères spéciaux. Ces règles doivent tenir compte des conventions spécifiques aux langues; tout le monde ne trie pas ses caractères dans ce que nous appellerions «l'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 utf8mb4_general_ci
tri simplifié dans MySQL, mais il y a encore quelques différences:
Par exemple, le classement Unicode trie "ß" comme "ss" et "Œ" comme "OE" comme le voudraient normalement les personnes utilisant ces caractères, alors qu'il les utf8mb4_general_ci
trie comme des caractères uniques (vraisemblablement comme "s" et "e" respectivement) .
Certains caractères Unicode sont définis comme ignorables, ce qui signifie qu'ils ne doivent pas compter dans l'ordre de tri et que la comparaison doit passer au caractère suivant à la place. utf8mb4_unicode_ci
les gère correctement.
Dans les langues non latines, telles que les langues asiatiques ou les langues avec différents alphabets, il peut y avoir beaucoup plus de différences entre le tri Unicode et le utf8mb4_general_ci
tri simplifié . L'adéquation de utf8mb4_general_ci
dépendra fortement de la langue utilisée. Pour certaines langues, ce sera tout à fait insuffisant.
Que devez-vous utiliser?
Il n'y a presque certainement aucune raison de l'utiliser utf8mb4_general_ci
, car nous avons laissé le point où la vitesse du processeur est suffisamment faible pour que la différence de performance soit importante. Votre base de données sera presque certainement limitée par d'autres goulots d'étranglement que celui-ci.
Dans le passé, certaines personnes recommandaient d'utiliser utf8mb4_general_ci
sauf lorsque le tri précis allait être suffisamment important pour justifier le coût des performances. Aujourd'hui, ce coût de performance a pratiquement disparu et les développeurs traitent l'internationalisation plus au sérieux.
Il y a un argument à faire valoir que si la vitesse est plus importante pour vous que la précision, vous pouvez tout aussi bien ne pas faire de tri du tout. Il est trivial de rendre un algorithme plus rapide si vous n'en avez pas besoin pour être précis. C'est donc utf8mb4_general_ci
un compromis qui n'est probablement pas nécessaire pour des raisons de vitesse et qui ne convient probablement pas non plus pour des raisons de précision.
Une autre chose que j'ajouterai est que même si vous savez que votre application ne prend en charge que la langue anglaise, elle peut encore avoir besoin de 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 à assurer la tranquillité d'esprit que les personnes Unicode très intelligentes ont travaillé très dur pour que le tri fonctionne correctement.
Que signifient les pièces
Premièrement, ci
est pour le tri et la comparaison insensibles à la casse . Cela signifie qu'il convient aux données textuelles et que la casse n'est pas importante. Les autres types de classement sont cs
(sensibles à la casse) pour les données textuelles où la casse est importante et bin
, lorsque le codage doit correspondre, bit pour bit, ce qui convient aux champs qui sont vraiment des données binaires codées (y compris, par exemple, Base64). Le tri sensible à la casse conduit à des résultats étranges et la comparaison sensible à la casse peut entraîner des valeurs en double ne différant que dans la casse des lettres, de sorte que les classements sensibles à la casse tombent en disgrâce pour les données textuelles - si la casse est importante pour vous, alors une ponctuation autrement ignorable et ainsi de suite est probablement également significatif, 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 façon dont le texte est normalisé ou comparé. Il existe de nombreux ensembles de règles différents pour l'encodage des caractères utf8mb4, unicode
et general
deux d'entre eux tentent de bien fonctionner dans toutes les langues possibles plutôt que dans une langue spécifique. Les différences entre ces deux ensembles de règles font l'objet de cette réponse. Notez que unicode
utilise les règles d'Unicode 4.0. Les versions récentes de MySQL ajoutent les ensembles de unicode_520
règles en utilisant les règles d'Unicode 5.2 et 0900
(en supprimant la partie "unicode_") en utilisant les règles d'Unicode 9.0.
Et enfin, utf8mb4
c'est bien sûr l'encodage de caractères utilisé en interne. Dans cette réponse, je ne parle que des encodages basés sur Unicode.
utf8_general_ci
: cela ne fonctionne tout simplement pas. C'est un retour au mauvais vieux temps de la stooopeeedity ASCII d'il y a cinquante ans. La correspondance insensible à la casse Unicode ne peut pas être effectuée sans la carte de casse de l'UCD. Par exemple, «Σίσυφος» contient trois sigmas différents; ou comment les minuscules de «TSCHüẞ» sont «tschüβ», mais les majuscules de «tschüβ» sont «TSCHÜSS». Vous pouvez avoir raison ou être rapide. Par conséquent, vous devez utiliser utf8_unicode_ci
, car si vous ne vous souciez pas de l'exactitude, il est trivial de le rendre infiniment rapide.
"か" == "が"
ou "ǽ" == "æ"
. Pour le tri, cela a du sens mais pourrait être surprenant lors de la sélection via des égalités ou du traitement d'indices uniques - bugs.mysql.com/bug.php?id=16526
utf8mb4
est le seul choix correct . Avec utf8
vous, vous êtes coincé dans une variante UTF8 de MySQL uniquement sur 3 octets que seuls MySQL (et MariaDB) savent quoi faire. Le reste du monde utilise UTF8, qui peut contenir jusqu'à 4 octets par caractère . Les développeurs MySQL ont mal nommé leur encodage homebrew utf8
et pour ne pas briser la compatibilité descendante, ils doivent maintenant se référer au vrai UTF8 utf8mb4
.
Je voulais savoir quelle est la différence de performances entre l'utilisation de utf8_general_ci
et utf8_unicode_ci
, mais je n'ai trouvé aucun benchmark répertorié sur Internet, j'ai donc décidé de créer moi-même des benchmarks.
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 de 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
J'ai ensuite créé les procédures stockées suivantes pour comparer les méthodes simples SELECT
, SELECT
avec LIKE
et de tri ( 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 ci-dessus, le utf8_general_ci
classement est utilisé, mais bien sûr, pendant les 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 calculé les valeurs moyennes.
Mes résultats sont:
benchmark_simple_select()
utf8_general_ci
: 9,957 ms utf8_unicode_ci
: 10,271 ms Dans cet indice de référence, l'utilisation utf8_unicode_ci
est plus lente que utf8_general_ci
de 3,2%.
benchmark_select_like()
utf8_general_ci
: 11,441 ms utf8_unicode_ci
: 12 811 ms Dans cette référence, l'utilisation utf8_unicode_ci
est plus lente que utf8_general_ci
de 12%.
benchmark_order_by()
utf8_general_ci
: 11 944 ms utf8_unicode_ci
: 12 887 ms Dans cet indice de référence, l'utilisation utf8_unicode_ci
est plus lente que utf8_general_ci
de 7,9%.
utf8_general_ci
est tout simplement trop minime pour être utile.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
ne génère que de l'ASCII et aucun caractère Unicode à traiter par les algorithmes des classements. 2) Description = 'test' COLLATE ...
et Description LIKE 'test%' COLLATE ...
ne traite qu'une seule chaîne ("test") au moment de l'exécution, n'est-ce pas? 3) Dans les applications réelles, les colonnes utilisées dans l'ordre seraient probablement indexées, et la vitesse d'indexation sur différents classements avec du texte réel non ASCII pourrait différer.
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 se traduit par des résultats de tri "moins précis".
utf8_unicode_ci
et prétendez que l'autre n'existe pas.
utf8_general_ci
peut-être pour vous
Voir le manuel mysql, section Jeux de caractères Unicode :
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 comme étant égal à des combinaisons d'autres caractères. Par exemple, en allemand et dans d'autres langues, «ß» est égal à «ss». utf8_unicode_ci prend également en charge 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 ou les caractères ignorables. Il ne peut faire que des comparaisons un à un entre les caractères.
Donc pour résumer, utf_general_ci utilise un ensemble de comparaisons plus petit et moins correct (selon la norme) que utf_unicode_ci qui devrait implémenter la norme entière. L'ensemble general_ci sera plus rapide car il y a moins de calcul à faire.
utf8_unicode_ci
et de faire semblant que la version cassée du buggy n'existe pas.
0
et 1
pas un booléen. :) Par exemple, la sélection de points géographiques dans un cadre de délimitation est une approximation des «points à proximité» qui n'est pas aussi bonne que le calcul de la distance entre le point et le point de référence et le filtrage sur celui-ci. Mais les deux sont une approximation et en fait, l'exactitude complète n'est généralement pas réalisable. Voir le paradoxe du littoral et IEEE 754
1/3
En bref:
Si vous avez besoin d'un meilleur ordre de tri - utilisez utf8_unicode_ci
(c'est la méthode préférée),
mais si vous êtes totalement intéressé par les performances - utilisez utf8_general_ci
, mais sachez que c'est un peu dépassé.
Les différences en termes de performances sont très légères.
Comme nous pouvons le lire ici ( Peter Gulutzan ), il y a une différence dans le tri / 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.
Il y a deux grandes différences entre le tri et la correspondance des caractères:
Tri :
utf8mb4_general_ci
supprime tous les accents et les trie un par un, ce qui peut créer des résultats de tri incorrects.utf8mb4_unicode_ci
trie précis.Correspondance de caractères
Ils correspondent aux caractères différemment.
Par exemple, en utf8mb4_unicode_ci
vous avez i != ı
, mais en utf8mb4_general_ci
elle tient ı=i
.
Par exemple, imaginez que vous avez une dispute avec name="Yılmaz"
. alors
select id from users where name='Yilmaz';
retournerait la ligne si la colocalisation est utf8mb4_general_ci
, mais si elle est colocalisée avec utf8mb4_unicode_ci
elle ne retournerait pas la ligne!
D'autre part , nous avons que a=ª
et ß=ss
dans ce utf8mb4_unicode_ci
qui est pas le cas utf8mb4_general_ci
. Alors imaginez que vous avez une dispute avec name="ªßi"
, alors
select id from users where name='assi';
renvoie la ligne si la colocalisation est utf8mb4_unicode_ci
, mais ne renvoie pas de ligne si la collocation est définie sur utf8mb4_general_ci
.
Une liste complète des correspondances pour chaque collocation peut être trouvée ici .
Selon cet article, il y a un avantage de performances considérablement important sur MySQL 5.7 lors de l'utilisation de utf8mb4_general_ci au lieu de utf8mb4_unicode_ci: https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql-performance /