UTF-8: Général? Poubelle? Unicode?

279

J'essaie de comprendre quel classement je devrais utiliser pour différents types de données. 100% du contenu que je vais stocker est soumis par l'utilisateur.

Ma compréhension est que je devrais utiliser UTF-8 General CI (insensible à la casse) au lieu de UTF-8 Binary. Cependant, je ne trouve pas de distinction claire entre UTF-8 General CI et UTF-8 Unicode CI.

  1. Dois-je stocker du contenu soumis par l'utilisateur dans des colonnes CI UTF-8 Général ou UTF-8 Unicode?
  2. À quel type de données le binaire UTF-8 serait-il applicable?
Dolph
la source
16
Remarque, mais au lieu de utf8, utilisez utf8mb4plutôt pour une prise en charge complète de l'UTF-8. Commenter ici parce que les réponses à cette question populaire ne répondent pas à cela. mathiasbynens.be/notes/mysql-utf8mb4
Steven R. Loomis
Si vous souhaitez un pliage de la casse, mais une sensibilité aux accents , veuillez déposer une demande sur bugs.mysql.com .
Rick James
Ou cliquez sur " M'affecte " sur bugs.mysql.com/bug.php?id=58797 et ajoutez un commentaire.
Rick James

Réponses:

299

En général, utf8_general_ci est plus rapide que utf8_unicode_ci , mais moins correct.

Voici la différence:

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.

Cité de: http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html

Pour une explication plus détaillée, veuillez lire l'article suivant sur les forums MySQL: http://forums.mysql.com/read.php?103,187048,188748

Quant à utf8_bin: utf8_general_ci et utf8_unicode_ci effectuent tous deux une comparaison insensible à la casse. En contraste , utf8_bin est sensible à la casse (entre autres différences), car il compare les valeurs binaires des caractères.

Sagi
la source
2
Je pense que si vous n'avez pas de bonnes raisons d'utiliser _unicode_ci, utilisez _general_ci.
Sagi
4
Cela ne répond cependant pas vraiment à la question en profondeur. Quelle est la différence entre ces classements exactement?
Pekka
4
Vous avez raison, la différence exacte n'est pas fournie ici par souci de simplicité. J'ai ajouté un lien vers un article avec la différence exacte .
Sagi
NB show collation;vous permet de voir le classement par défaut pour chaque jeu de caractères. 5.1 s'affiche utf8_general_cipar défaut pour utf8.
David Carboni
9
Existe-t-il des ressources qui pourraient approfondir la différence de vitesse réelle entre les deux classements? Parlons-nous d'une baisse de 0,1% des performances ou d'une baisse de 10%?
Emphram Stavanger
90

Vous devez également être conscient du fait qu'avec utf8_general_ci lorsque vous utilisez un champ varchar comme index unique ou primaire, l'insertion de 2 valeurs comme 'a' et 'á' donnerait une erreur de clé en double.

Alex Hepp
la source
3
Merci, cela est utile pour éviter des noms d'utilisateur similaires (par exemple, si "jose" existe, je ne voudrais pas que quelqu'un d'autre crée un utilisateur "josé") NB: cela vaut également pour la plupart des classements utf8 (sauf utf8_bin). Le plus sûr / le plus sûr / le plus complet estutf8_unicode_ci
Costa
2
J'utilise utf8_bin où je veux que jose et jose soient distingués dans l'index. Par exemple, une colonne qui enregistre les opérations de recherche / remplacement, où l'utilisateur peut avoir décidé de rechercher josé et de le remplacer par jose. (J'écris un tableur)
Buttle Butkus
33
  • utf8_bincompare les bits à l'aveugle. Pas de pliage de boîtier, pas de décapage d'accent.
  • utf8_general_cicompare un octet à un octet. Il inclut le pliage et la suppression d'accentuation, mais aucune comparaison à 2 caractères: ijn'est pas égal ijdans ce classement.
  • utf8_*_ciest un ensemble de règles spécifiques à la langue, mais sinon comme unicode_ci. Quelques cas particuliers: Ç, Č, ch,ll
  • utf8_unicode_cisuit un ancien standard Unicode pour les comparaisons. ij= ij, mais ae! =æ
  • utf8_unicode_520_cisuit une nouvelle norme Unicode. ae=æ

Voir le tableau de classement pour plus de détails sur ce qui est égal à quoi dans divers classements utf8.

utf8, tel que défini par MySQL, est limité aux codes utf8 de 1 à 3 octets. Cela laisse de côté Emoji et certains chinois. Vous devriez donc vraiment passer à utf8mb4si vous voulez aller bien au-delà de l'Europe.

Les points ci-dessus s'appliquent à utf8mb4, après un changement d'orthographe approprié. Aller de l'avant, utf8mb4et utf8mb4_unicode_520_cisont préférés.

  • utf16 et utf32 sont des variantes de utf8; il n'y a pratiquement aucune utilité pour eux.
  • ucs2 est plus proche de "Unicode" que de "utf8"; il est pratiquement inutile.
Rick James
la source
1
Re "restez à l'écoute": les classements 8.0 montrent comment différents caractères, diphtongues, etc., se comparent dans les classements 8.0 utf8mb4; utf8 est essentiellement le même.
Rick James
Et les classements 8.0 sont cadencés à être nettement plus rapides que 5.x.
Rick James
ce serait bien si cette page répertorie utf8mb4_bin en haut. Je sais que cela ne correspond à aucun caractère, mais c'est bon pour les débutants.
Henk Poley
6

Vraiment, j'ai testé les valeurs de sauvegarde comme 'é' et 'e' dans la colonne avec un index unique et elles provoquent des erreurs en double sur 'utf8_unicode_ci' et 'utf8_general_ci'. Vous ne pouvez les enregistrer que dans la colonne assemblée «utf8_bin».

Et les documents mysql (dans http://dev.mysql.com/doc/refman/5.7/en/charset-applications.html ) suggèrent dans ses exemples un ensemble de collations 'utf8_general_ci'.

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
vitalii
la source
1
J'ai fait un test rapide à ce sujet, et il semble être exact. Les deux classements se comportent de la même manière lorsqu'il s'agit d'une clé unique sur une colonne et de valeurs avec des tildes et similaires.
MirroredFate
@MirroredFate OK, je dois ajouter que cette colonne doit avoir un index unique pour provoquer cette erreur. Cela implique dans ma réponse.
vitalii
3

La réponse acceptée est obsolète.

Si vous utilisez MySQL 5.5.3+, utilisez utf8mb4_unicode_ciplutôt que utf8_unicode_cipour vous assurer que les caractères saisis par vos utilisateurs ne vous donneront pas d'erreurs.

utf8mb4prend en charge les emojis par exemple, alors qu'il utf8pourrait vous donner des centaines de bogues liés à l'encodage comme:

Incorrect string value: ‘\xF0\x9F\x98\x81…’ for column ‘data’ at row 1

Marwann
la source
Cette réponse (correctement) résout les problèmes d'encodage des emoji (et de certains chinois). Mais la question semble se concentrer sur la collation. utf8mb4_unicode_citraite (je pense) tous les Emoji comme égaux. utf8mb4_unicode_520_cidonne un ordre à Emoji.
Rick James