2017-03-21 5 views
0

Je suis en train de convertir une base de données à utiliser utf8mb4 au lieu de UTF8. Tout va bien, sauf une table:double erreurs de saisie lors de la conversion de la base de données UTF8 à utf8mb4

CREATE TABLE `search_terms` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `search_term` varchar(128) NOT NULL, 
    `time_added` timestamp NULL DEFAULT NULL, 
    `count` int(10) unsigned NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `search_term` (`search_term`), 
    KEY `search_term_count` (`count`) 
) ENGINE=InnoDB AUTO_INCREMENT=198981 DEFAULT CHARSET=utf8; 

Fondamentalement, il ne fait enregistrer une entrée chaque fois que quelqu'un recherche quelque chose sous une forme afin que nous puissions suivre le nombre de recherches, très simples.

Il y a un index unique sur search_term parce que nous voulons avoir seulement une ligne par terme de recherche et incrémenter au lieu de la valeur de comptage.

Cependant lors de la conversion à utf8mb4 Je reçois des erreurs d'entrée en double. Voici la commande que je suis en cours d'exécution:

ALTER TABLE `search_terms` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 

En regardant dans la base de données que je peux voir divers exemples comme celui-ci:

fm2012

fm2012

fm2012

Dans son jeu de caractères utf8 actuel, ceux-ci sont al l être traité comme unique et exister dans la base de données sans jamais avoir un problème avec l'index unique sur search_term.

Mais lors de la conversion à utf8mb4 ils sont considérés comme étant égaux et maintenant lancer une erreur due à cet indice.

je peux comprendre comment fusionner ces ensemble assez facilement, mais je suis préoccupé par ce qui peut être un symptôme d'un problème plus fondamental. Je ne suis pas vraiment sûr comment cela est arrivé ou quelles peuvent être les conséquences, donc mes questions sont un peu vagues:

  1. Pourquoi utf8mb4 traite-t-il différemment de utf8?
  2. Quelles sont les conséquences possibles?
  3. Y at-il someway je peux faire une conversion si des choses comme « fm2012 » apparaissent jamais dans ma base de données et je ne « fm2012 » (je suis également en utilisant Laravel 5,1)
+0

Cela ressemble plus à UTF-32 et UTF-16 pour être honnête.C'est étrange que la conversion le fasse. Est-ce que cela se produit sur des tables de test triviales? – tadman

+0

Pourriez-vous s'il vous plaît coller votre erreur? –

+0

Quel est le classement avant la conversion et sont-ils vraiment des espaces dans votre exemple de chaîne "fm2012"? Pouvez-vous nous obtenir la décharge hexagonale? – Beat

Répondre

1

Votre problème est le changement de la collation : vous utilisez general_ci et vous convertissez à unicode_ci: general_ci est tout à fait une collation simple qui ne sait pas grand chose sur unicode, mais unicode_ci fait. Le premier "f" dans votre exemple de chaîne est un "Full Fidth Latin F" (U + FF46) qui est considéré comme égal à "Latin Small Letter F" (U + 0066) par unicode_ci mais pas par general_ci.

Normalement, il est recommandé d'utiliser unicode_ci exactement à cause de sa conscience d'unicode, mais vous pouvez convertir en utf8mb4_general_ci pour éviter ce problème.

Pour éviter ce problème à l'avenir, vous devriez normalize votre entrée avant de l'enregistrer dans la base de données. Normalement, vous utiliseriez NFC, mais votre cas semble appeler NFKC. Cela devrait amener toutes les chaînes "équivalentes" à la même forme.

+0

Ah, merci beaucoup qui a du sens. Y a-t-il d'autres différences dans l'utilisation de utf8mb4_general_ci au lieu de utf8mb4_unicode_ci? Cela semble être une bonne opportunité pour faire le changement mais je suppose que cela pourrait aussi causer plus de problèmes. – robjbrain

+0

Il existe de nombreuses différences, voir http://stackoverflow.com/a/2344130/853468 – Beat