mysql utf8mb4 - Quelle est la différence entre utf8_general_ci et utf8_unicode_ci




collate ut8mb4 (5)

Entre utf8_general_ci et utf8_unicode_ci , y a-t-il des différences en termes de performance?


Answers

Ce post le décrit très bien.

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


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

Note: Depuis MySQL 5.5.3, vous devriez utiliser utf8mb4 plutôt que utf8 . Ils se réfèrent tous les deux à l'encodage UTF-8, mais l' utf8 plus ancien avait une limitation spécifique à MySQL empêchant l'utilisation des caractères numérotés au-dessus de 0xFFFD.

  • Précision

    utf8mb4_unicode_ci est basé sur la norme Unicode pour le tri et la comparaison, qui trie avec précision dans un très large éventail de langues.

    utf8mb4_general_ci ne parvient pas à implémenter toutes les règles de tri Unicode, ce qui entraînera un tri indésirable dans certaines situations, comme lors de l'utilisation de langages ou de caractères particuliers.

  • Performance

    utf8mb4_general_ci est plus rapide dans les comparaisons et le tri, car il prend un tas de raccourcis liés aux performances.

    Sur les serveurs modernes, cette amélioration des performances sera tout sauf négligeable. Il a été conçu à une époque où les serveurs avaient une infime fraction de la performance du processeur des ordinateurs d'aujourd'hui.

    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 prendre en compte les conventions spécifiques à la langue; pas tout le monde trie leurs caractères dans ce que nous appellerions «ordre alphabétique».

En ce qui concerne les langues latines (ie "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 y a encore quelques différences:

  • Par exemple, le classement Unicode trie "ß" comme "ss", et "Œ" comme "OE" car les gens qui utilisent ces caractères voudraient normalement, alors que utf8mb4_general_ci trie comme des caractères simples (vraisemblablement comme "s" et "e" respectivement ).

  • Certains caractères Unicode sont définis comme 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 gère correctement.

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

Que devriez-vous utiliser?

Il n'y a presque certainement plus de raison d'utiliser utf8mb4_general_ci , car nous avons laissé derrière nous 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.

La différence de performance ne sera mesurable que dans des situations extrêmement spécialisées, et si c'est vous, vous le savez probablement déjà. Si vous rencontrez un problème de tri, dans la plupart des cas, il y aura un problème avec vos index / plan de requête. Changer votre fonction de classement ne devrait pas être en haut de la liste des choses à dépanner.

Dans le passé, certaines personnes recommandaient d'utiliser utf8mb4_general_ci sauf quand un tri précis était suffisant pour justifier le coût de la performance. Aujourd'hui, ce coût de performance a pratiquement disparu et les développeurs traitent l'internationalisation plus sérieusement.

Une autre chose que j'ajouterai est que même si vous savez que votre application ne supporte que l'anglais, elle peut toujours avoir besoin de gérer les noms des personnes, qui peuvent souvent contenir des caractères utilisés dans d'autres langues dans lesquelles il est important de trier correctement . L'utilisation des règles Unicode pour tout contribue à la tranquillité d'esprit que les personnes très intelligentes d'Unicode ont travaillé très dur pour que le tri fonctionne correctement.


En quelques mots:

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 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.


Je voulais savoir quelle est la différence de performance entre utf8_general_ci et utf8_unicode_ci, mais je n'ai trouvé aucun benchmark sur Internet, j'ai donc décidé de créer moi-même des benchmarks.

J'ai créé une table 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 référencer SELECT simple, SELECT avec LIKE et tri (SELECT avec ORDER BY):

CREATE 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 utf8_general_ci collation 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 j'ai calculé les valeurs moyennes.

Mes résultats sont:

benchmark_simple_select () avec utf8_general_ci: 9957 ms
benchmark_simple_select () avec utf8_unicode_ci: 10271 ms
Dans ce cas-test, utf8_unicode_ci est plus lent que utf8_general_ci de 3,2%.

benchmark_select_like () avec utf8_general_ci: 11441 ms
benchmark_select_like () avec utf8_unicode_ci: 12811 ms
Dans ce cas-test, utf8_unicode_ci est plus lent que utf8_general_ci de 12%.

benchmark_order_by () avec utf8_general_ci: 11944 ms
benchmark_order_by () avec utf8_unicode_ci: 12887 ms
Dans ce cas-test, utf8_unicode_ci est plus lent que utf8_general_ci de 7,9%.


MySQL a le concept de variables définies par l'utilisateur .

Ce sont des variables faiblement typées qui peuvent être initialisées quelque part dans une session et conserver leur valeur jusqu'à la fin de la session.

Ils sont précédés d'un signe @ , comme ceci: @var

Vous pouvez initialiser cette variable avec une instruction SET ou à l'intérieur d'une requête:

SET @var = 1

SELECT @var2 := 2

Lorsque vous développez une procédure stockée dans MySQL , vous pouvez passer les paramètres d'entrée et déclarer les variables locales:

DELIMITER //

CREATE PROCEDURE prc_test (var INT)
BEGIN
    DECLARE  var2 INT;
    SET var2 = 1;
    SELECT  var2;
END;
//

DELIMITER ;

Ces variables ne sont ajoutées à aucun préfixe.

La différence entre une variable de procédure et une variable définie par l'utilisateur spécifique à une session est que la variable de procédure est réinitialisée à NULL chaque fois que la procédure est appelée, alors que la variable spécifique à la session n'est pas:

CREATE PROCEDURE prc_test ()
BEGIN
    DECLARE var2 INT DEFAULT 1;
    SET var2 = var2 + 1;
    SET @var2 = @var2 + 1;
    SELECT  var2, @var2;
END;

SET @var2 = 1;

CALL prc_test();

var2  @var2
---   ---
2     2


CALL prc_test();

var2  @var2
---   ---
2     3


CALL prc_test();

var2  @var2
---   ---
2     4

Comme vous pouvez le voir, var2 (variable de procédure) est réinitialisé à chaque appel de la procédure, alors que @var2 (variable spécifique à la session) ne l'est pas.

(En plus des variables définies par l'utilisateur, MySQL a également des "variables système" prédéfinies, qui peuvent être des "variables globales" telles que @@global.port ou des "variables de session" telles que @@session.sql_mode ; "ne sont pas liés aux variables définies par l'utilisateur propres à la session."





mysql unicode