Formation PUB030 : Laravel, 2019 Mise en ligne Laravel

14.5 utf8 vs utf8mb4, ou comment éviter l'erreur « #1071 - La clé est trop longue. Longueur maximale: 767 »


La version de MySQL que vous utilisez pendant votre développement (ex : MySQL 5.7.7) pourrait être différente de celle qui est utilisée sur votre serveur de production.

Parfois, même, le serveur de production utilisera MariaDB plutôt que MySQL. La compatibilité entre MariaDB et MySQL est très élevée alors les problèmes sont plutôt rares.

Généralement, ceci a peu ou pas d'impacts sur votre application. Mais dans certains cas, vous devrez apporter quelques ajustements.

Vous pouvez connaître la version de MySQL à l'aide de la commande :

MySQL

SELECT VERSION();

La commande SELECT @@version; donnera le même résultat.

Vous pouvez lancer la commande SHOW VARIABLES; pour connaître la valeur des différentes configurations.

Erreur 1071 - La clé est trop longue

Le cas qui nous intéresse ici, c'est lorsque vous tentez de créer ou de modifier une table MySQL chez votre hébergeur et que vous obtenez le message « #1071 - La clé est trop longue. Longueur maximale: 767 ». En anglais, on aura plutôt l'erreur « Specified key was too long; max key length is 767 bytes. ».

La clé est trop longue. Longueur maximale: 767

Le problème dans cette situation, c'est que vous tentez de créer un index (clé primaire, index unique, index de recherche, etc.) sur un champ dont la taille dépasse la longueur maximale permise.

La longueur maximale dépend du moteur utilisé. Avec un moteur InnoDB, elle est de 767 octets. Avec un moteur MyISAM, elle est de 1000 octets.

Le nombre d'octets pour un champ VARCHAR dépendra de l'encodage. Avec UTF-8, chaque caractère peut prendre jusqu'à 3 octets. Avec utf8mb4, chaque caractère peut prendre jusqu'à 4 octets.

Ainsi, avec UTF-8 et InnoDB, la taille maximale pour un index est VARCHAR(255), ce qui donne 255 x 3 = 765 octets. Avec VARCHAR(256), on tomberait à 768, ce qui est trop grand.

Avec utf8mb4 et InnoDB, la taille maximale pour un index est VARCHAR(191), ce qui donne 191 x 4 = 764 octets. Avec VARCHAR(192), on dépasserait la limite car on aurait 768 octets.

Depuis MySQL 5.7.7, la limite pour les index a été augmentée. Ceci peut expliquer le fait que votre code fonctionne dans votre environnement de développement (qui utilise une version récente de MySQL) mais pas chez votre hébergeur (s'il utilise une version moins récente).

Vous avez plusieurs choix pour régler ce problème :

  • changer l'encodage (Avez-vous vraiment besoin de utf8mb4 ? Nécessaire seulement si vous désirez enregistrer certains caractères spéciaux encodés sur 4 octets, par exemple des émoticônes.) Notez que si vous tentez d'enregistrer un symbole qui nécessite 4 octets alors que l'encodage n'en permet que 3, vous obtiendrez un message du genre « Incorrect string value: '\xF0\x9F\x98\x8A' ».

    Ex :

    MySQL

    CREATE TABLE `users` (
        `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
        `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
        `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
        `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
        `remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
        `created_at` timestamp NULL DEFAULT NULL,
        `updated_at` timestamp NULL DEFAULT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY `users_email_unique` (`email`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

    ou

  • ajuster la taille des champs sur lesquels vous désirez placer un index (avez-vous vraiment besoin d'autant de caractères ?)

    ou

  • changer le moteur (attention : MyISAM ne permet pas de gérer les contraintes d'intégrité référentielle).

Notez qu'à partir de MySQL 5.6, est possible de configurer le serveur pour augmenter cette limite mais si votre site est en hébergement partagé, cette solution n'est pas disponible pour vous.

Pour plus d'information

« Converting Between 3-Byte and 4-Byte Unicode Character Sets ». MySQL. https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-conversion.html

« The utf8mb4 Character Set (4-Byte UTF-8 Unicode Encoding) ». MySQL. https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb4.html

« How to support full Unicode in MySQL databases ». Mathias Bynens. https://mathiasbynens.be/notes/mysql-utf8

« PHP La bonne manière - UTF-8 au niveau de la base de données ». PHP La bonne manière. http://eilgin.github.io/php-the-right-way/#utf-8-au-niveau-de-la-base-de-donn%C3%A9es

« Limits on InnoDB Tables ». MySQL. https://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html#innodb-mximums-minimums

« Limits - 767 Limit in InnoDB Indexes ». Rick James. http://mysql.rjweb.org/doc.php/limits#767_limit_in_innodb_indexes

« InnoDB Startup Options and System Variables ». MySQL. https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_file_format

▼Publicité

Veuillez noter que le contenu de cette fiche vous est partagé à titre gracieux, au meilleur de mes connaissances et sans aucune garantie.
Merci de partager !
Soumettre