15%

Économisez 15% sur tous les services d'hébergement

Testez vos compétences et obtenez Réduction sur tout plan d'hébergement

Utilisez le code :

Skills
Commencer
08.10.2024

utf8 vs utf8mb4 dans MySQL : Le Guide Technique Complet

Le jeu de caractères utf8 de MySQL est un terme impropre — ce n’est pas une véritable implémentation UTF-8. Il encode les caractères en utilisant seulement 1 à 3 octets, ce qui signifie qu’il abandonne ou rejette silencieusement tout point de code Unicode supérieur à U+FFFF, y compris tous les emoji et une partie significative des caractères CJK supplémentaires. utf8mb4 est l’implémentation UTF-8 correcte et complète de MySQL, prenant en charge 1 à 4 octets par caractère et la plage Unicode complète. Pour toute base de données de production créée après 2010, utf8mb4 est le seul choix défendable.

Ce guide explique précisément pourquoi cette distinction est importante, où la conception originale d’utf8 a échoué, comment migrer en toute sécurité, et comment configurer MySQL correctement au niveau du serveur, de la base de données, de la table et de la connexion.

Le problème fondamental : pourquoi l’utf8 de MySQL est défectueux par conception

La norme d’encodage UTF-8 (RFC 3629) définit un schéma à largeur variable qui utilise 1 à 4 octets pour représenter chaque point de code Unicode valide — plus de 1,1 million de caractères possibles. Lorsque MySQL a introduit son jeu de caractères `utf8` dans la version 4.1, l’implémentation a été intentionnellement limitée à 3 octets par caractère. Il s’agissait d’un raccourci d’ingénierie délibéré, et non d’une omission.

À l’époque, le format de ligne InnoDB imposait une limite de 767 octets sur les préfixes de clés d’index. La prise en charge de caractères sur 4 octets aurait réduit la longueur maximale du préfixe indexé pour les colonnes `VARCHAR`, créant des problèmes de compatibilité d’index. La limite à 3 octets était une solution pragmatique qui est devenue un passif à long terme.

La conséquence pratique : tout point de code Unicode dans le Plan Multilingue Supplémentaire (SMP) — les points de code U+10000 et au-delà — ne peut pas être stocké dans une colonne `utf8`. Cela inclut :

  • Tous les emoji standard (U+1F600 et au-delà)
  • Les symboles alphanumériques mathématiques (U+1D400–U+1D7FF)
  • Les symboles de notation musicale
  • Les écritures historiques telles que le Linéaire B, le Gotique et le Cunéiforme
  • Les idéogrammes CJK unifiés supplémentaires (U+20000–U+2A6DF)
  • Certains symboles monétaires et opérateurs techniques ajoutés dans les versions récentes d’Unicode

Lorsqu’une application tente d’insérer un caractère sur 4 octets dans une colonne `utf8`, MySQL renvoie soit une erreur `Incorrect string value`, soit, si `sql_mode` est permissif, tronque silencieusement les données. La troncature silencieuse est sans doute le résultat le plus dangereux — votre application ne reçoit aucune erreur, mais vos données sont corrompues.

utf8mb4 : l’implémentation correcte

MySQL a introduit utf8mb4 dans la version 5.5.3 (publiée en 2010) spécifiquement pour remédier à cette lacune. Le suffixe `mb4` signifie « multi-octets, 4 octets maximum ». Il s’agit d’un sur-ensemble strict de `utf8` — chaque caractère représentable dans `utf8` est identiquement représentable dans `utf8mb4`. Il n’y a aucune perte de données lors de la migration de `utf8` vers `utf8mb4`.

utf8mb4 correspond directement à la norme UTF-8 RFC 3629. Il gère l’espace de codes Unicode complet de U+0000 à U+10FFFF sans restriction.

utf8 vs utf8mb4 : comparaison des fonctionnalités

Fonctionnalitéutf8 (MySQL)utf8mb4
Octets par caractère1–31–4
Couverture UnicodeBMP uniquement (U+0000–U+FFFF)Complète (U+0000–U+10FFFF)
Prise en charge des emojiNonOui
CJK supplémentaireNonOui
Conforme RFC 3629NonOui
Préfixe d’index max (InnoDB, pages 4KB)767 octets767 octets (191 caractères)
Préfixe d’index max (innodb_large_prefix)3072 octets3072 octets (768 caractères)
Surcharge de stockage vs latin1Identique pour ASCIIIdentique pour ASCII
Recommandé pour les nouveaux projetsNonOui
Version MySQL d’introduction4.15.5.3

Choix de collation dans utf8mb4

Choisir utf8mb4 comme jeu de caractères n’est que la moitié de la décision. La collation détermine comment les chaînes sont comparées, triées et indexées. Une collation incorrecte provoque un comportement de requête subtil et difficile à déboguer.

utf8mb4_unicode_ci

Basée sur l’Algorithme de Collation Unicode (UCA). Gère correctement les règles de tri spécifiques aux langues. Légèrement plus lente que `utf8mb4_general_ci` en raison d’une logique de comparaison plus complexe, mais la différence de performance est négligeable sur le matériel moderne.

utf8mb4_general_ci

Une collation simplifiée qui n’implémente pas entièrement l’UCA. Plus rapide dans les benchmarks du début des années 2010, mais l’avantage de vitesse est sans pertinence sur les CPU actuels. Elle gère incorrectement certains cas limites — par exemple, elle traite certains caractères allemands comme équivalents alors qu’ils ne devraient pas l’être. À éviter pour les nouveaux projets.

utf8mb4_0900_ai_ci

Disponible dans MySQL 8.0+. Basée sur Unicode 9.0 avec une comparaison insensible aux accents (`ai`) et insensible à la casse (`ci`). Il s’agit du défaut recommandé pour MySQL 8.0 et versions ultérieures. Elle est plus rapide que `utf8mb4_unicode_ci` et plus précise.

utf8mb4_bin

Comparaison binaire — sensible à la casse, sensible aux accents, sans règles spécifiques aux paramètres régionaux. À utiliser lorsque vous avez besoin d’une correspondance exacte au niveau des octets, comme pour les hachages de mots de passe ou les identifiants sensibles à la casse.

Recommandation : Utilisez `utf8mb4_0900_ai_ci` sur MySQL 8.0+. Utilisez `utf8mb4_unicode_ci` sur MySQL 5.7 et versions antérieures.

Implications sur le stockage et les index

Une préoccupation courante lors de la migration d’utf8 vers utf8mb4 est la surcharge de stockage. En pratique, l’impact est minimal :

  • Les caractères ASCII (U+0000–U+007F) occupent toujours exactement 1 octet dans les deux encodages.
  • La plupart des caractères latins, grecs, cyrilliques, arabes et hébreux occupent 2 octets dans les deux encodages.
  • Les caractères CJK dans le BMP occupent 3 octets dans les deux encodages.
  • Seuls les caractères supplémentaires (emoji, CJK supplémentaire) nécessitent 4 octets — et ceux-ci étaient simplement non représentables dans utf8 auparavant.

La véritable préoccupation concernant les index est la limite de préfixe d’index InnoDB de 767 octets sur les configurations plus anciennes. Avec utf8mb4, un cas le plus défavorable de 4 octets par caractère signifie qu’un préfixe d’index `VARCHAR` de 191 caractères atteint le plafond de 767 octets. Avec `utf8`, le même plafond permettait 255 caractères. Si vous avez des colonnes `VARCHAR(255)` avec des index sur la colonne complète, vous pourriez rencontrer des erreurs `Specified key was too long` lors de la migration.

Solutions :

  • Activez `innodb_large_prefix = ON` (MySQL 5.6/5.7) pour porter la limite à 3072 octets.
  • Utilisez `ROW_FORMAT=DYNAMIC` ou `ROW_FORMAT=COMPRESSED` sur les tables concernées.
  • Dans MySQL 8.0, `innodb_large_prefix` est activé par défaut et le paramètre est supprimé.
  • Raccourcissez les préfixes d’index : `INDEX (column(191))` au lieu de `INDEX (column(255))`.

Il s’agit du point d’échec de migration le plus courant et celui le plus fréquemment sous-documenté dans les guides de base.

Comment migrer une base de données MySQL d’utf8 vers utf8mb4

La migration est simple mais nécessite de la précision. Ignorer n’importe quelle couche — serveur, base de données, table ou connexion — laisse votre application revenir silencieusement à l’ancien encodage.

Étape 1 : Sauvegarder la base de données

Ne modifiez jamais l’encodage des caractères sur une base de données en production sans une sauvegarde vérifiée.

“`bash

mysqldump -u username -p –single-transaction –routines –triggers

database_name > database_backup_$(date +%F).sql

“`

L’option `–single-transaction` garantit un instantané cohérent pour les tables InnoDB sans verrouillage. Stockez la sauvegarde dans un emplacement séparé du serveur de base de données avant de continuer.

Étape 2 : Mettre à jour la configuration du serveur MySQL

Modifiez `/etc/mysql/my.cnf` ou `/etc/mysql/mysql.conf.d/mysqld.cnf` selon votre distribution :

“`ini

[client]

default-character-set = utf8mb4

[mysql]

default-character-set = utf8mb4

[mysqld]

character-set-server = utf8mb4

collation-server = utf8mb4_unicode_ci

For MySQL 5.6/5.7 only — remove on MySQL 8.0

innodb_large_prefix = ON

innodb_file_format = Barracuda

innodb_file_per_table = ON

“`

Redémarrez MySQL :

“`bash

sudo systemctl restart mysql

“`

Étape 3 : Convertir la base de données

“`sql

ALTER DATABASE database_name

CHARACTER SET = utf8mb4

COLLATE = utf8mb4_unicode_ci;

“`

Étape 4 : Convertir toutes les tables

Générez et exécutez des instructions `ALTER TABLE` pour chaque table. Les exécuter manuellement sur des schémas volumineux est source d’erreurs. Utilisez cette requête pour générer les instructions automatiquement :

“`sql

SELECT CONCAT(

'ALTER TABLE `', TABLE_NAME, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'

)

FROM information_schema.TABLES

WHERE TABLE_SCHEMA = 'database_name'

AND TABLE_TYPE = 'BASE TABLE';

“`

Exécutez chaque instruction générée. La syntaxe `CONVERT TO CHARACTER SET` modifie à la fois le défaut de la table et toutes les colonnes de caractères existantes en une seule opération.

Étape 5 : Corriger les erreurs de longueur d’index

Si vous rencontrez `Specified key was too long; max key length is 767 bytes`, identifiez l’index problématique :

“`sql

— Change full-column index to prefix index

ALTER TABLE table_name DROP INDEX index_name;

ALTER TABLE table_name ADD INDEX index_name (column_name(191));

“`

Pour les bases de données WordPress spécifiquement, la colonne `option_name` de la table `wp_options` et la colonne `meta_key` de `wp_postmeta` sont des sources courantes de cette erreur.

Étape 6 : Vérifier la conversion

“`sql

— Check server-level variables

SHOW VARIABLES LIKE 'character_set%';

SHOW VARIABLES LIKE 'collation%';

— Check a specific table

SHOW CREATE TABLE table_nameG

— Check all columns in a database

SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME

FROM information_schema.COLUMNS

WHERE TABLE_SCHEMA = 'database_name'

AND DATA_TYPE IN ('char', 'varchar', 'text', 'tinytext', 'mediumtext', 'longtext');

“`

Chaque valeur `CHARACTER_SET_NAME` devrait afficher `utf8mb4`.

Étape 7 : Mettre à jour les chaînes de connexion de l’application

L’encodage du serveur et du schéma ne signifie rien si votre application se connecte en utilisant le mauvais jeu de caractères. L’encodage au niveau de la connexion remplace le défaut du serveur.

PHP (PDO) :

“`php

$dsn = 'mysql:host=localhost;dbname=database_name;charset=utf8mb4';

$pdo = new PDO($dsn, $user, $pass, [

PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"

]);

“`

PHP (MySQLi) :

“`php

$mysqli = new mysqli('localhost', $user, $pass, $db);

$mysqli->set_charset('utf8mb4');

“`

Python (mysql-connector-python) :

“`python

cnx = mysql.connector.connect(

host='localhost', user=user, password=pass,

database=db, charset='utf8mb4', collation='utf8mb4_unicode_ci'

)

“`

Node.js (mysql2) :

“`javascript

const pool = mysql2.createPool({

host: 'localhost', user: user, password: pass,

database: db, charset: 'utf8mb4'

});

“`

Ne pas définir le jeu de caractères de connexion est la raison la plus courante pour laquelle les emoji échouent encore à être insérés après une migration supposément complète.

Considérations spécifiques à WordPress

WordPress utilise utf8mb4 comme jeu de caractères par défaut depuis la version 4.2 (avril 2015). Si vous exécutez une installation WordPress sur une ancienne base de données qui n’a jamais été migrée, le fichier `wp-config.php` peut encore contenir :

“`php

define('DB_CHARSET', 'utf8');

“`

Changez ceci en :

“`php

define('DB_CHARSET', 'utf8mb4');

define('DB_COLLATE', 'utf8mb4_unicode_ci');

“`

WordPress inclut également une routine de mise à niveau intégrée (`maybe_convert_table_to_utf8mb4()`) qui s’exécute lors des mises à jour du cœur. Cependant, cette routine ne capture pas toujours chaque table, en particulier celles créées par des extensions. L’approche manuelle `ALTER TABLE` décrite ci-dessus est plus fiable.

Sur un environnement Hébergement VPS avec accès root, vous pouvez automatiser l’intégralité de ce processus avec un script shell et le planifier comme une tâche cron unique, vous donnant un contrôle total sur le calendrier et la journalisation.

Considérations de performance

L’impact sur les performances d’utf8mb4 par rapport à utf8 est négligeable pour la grande majorité des charges de travail :

  • Requêtes de lecture : Aucune différence mesurable pour les caractères BMP. Les caractères supplémentaires nécessitent un octet d’E/S supplémentaire, qui est absorbé par la mise en cache du pool de tampons.
  • Requêtes d’écriture : Identiques pour le contenu ASCII et BMP. Marginalement plus élevées pour les caractères supplémentaires.
  • Opérations d’index : La longueur maximale de préfixe réduite (191 vs 255 caractères pour les index sur colonne complète) peut affecter les plans de requête si vous avez des index sur colonne complète sur de longues colonnes `VARCHAR`. Auditez vos index avant et après la migration.
  • Mémoire : MySQL alloue des tampons de largeur fixe pour les opérations sur les chaînes en fonction du nombre maximum d’octets par caractère. Le passage d’utf8 (3 octets max) à utf8mb4 (4 octets max) augmente la mémoire allouée pour les tampons de tri en mémoire et les tables temporaires d’environ 33 % pour les opérations intensives en chaînes. Sur un Serveur Dédié avec suffisamment de RAM, cela est sans conséquence. Dans un environnement partagé à mémoire limitée, surveillez `sort_buffer_size` et `tmp_table_size` après la migration.

Quand utf8 est encore acceptable

Il existe un ensemble restreint de raisons légitimes de conserver `utf8` :

  • Compatibilité stricte avec les systèmes hérités : Une application utilisant un ORM ou un pilote de base de données non maintenu qui ne peut pas gérer les caractères sur 4 octets. Il s’agit d’un problème de dette technique, pas d’une raison de conserver utf8 indéfiniment.
  • Bases de données d’archivage en lecture seule : Si une base de données ne recevra jamais de nouvelles écritures et que les données existantes ne contiennent pas de caractères supplémentaires, la migration ajoute un risque sans bénéfice.
  • Contraintes de stockage strictes : Dans des cas extrêmes — systèmes embarqués ou environnements à capacité très limitée — la différence de stockage marginale pourrait avoir de l’importance. Cela ne s’applique à aucun scénario d’hébergement web standard.

Dans tous les autres cas, utf8mb4 est le bon choix. L’argument selon lequel utf8 économise de l’espace de stockage n’est techniquement vrai que pour les caractères supplémentaires, qui étaient de toute façon non représentables dans utf8. Vous n’économisez pas d’espace sur des données que vous ne pouviez pas stocker.

Choisir le bon environnement d’hébergement pour MySQL utf8mb4

Une configuration utf8mb4 correcte nécessite l’accès au fichier de configuration du serveur MySQL (`my.cnf`). Cela exclut la plupart des environnements d’hébergement partagé où vous ne pouvez pas modifier les variables au niveau du serveur.

Pour un contrôle total sur l’encodage des caractères MySQL, la collation, les paramètres InnoDB et les paramètres de connexion, vous avez besoin soit d’un plan Hébergement VPS avec accès root, soit d’un Serveur Dédié. Les deux vous donnent un accès direct à `/etc/mysql/my.cnf`, la possibilité de redémarrer le service MySQL, et la liberté de configurer `innodb_large_prefix`, `ROW_FORMAT` et d’autres paramètres qui affectent le succès de la migration vers utf8mb4.

Si vous gérez plusieurs bases de données ou sites clients, un VPS avec cPanel fournit une interface graphique pour la gestion des bases de données tout en conservant l’accès sous-jacent au serveur nécessaire pour la configuration du jeu de caractères. Pour les équipes qui préfèrent la flexibilité de la ligne de commande avec un panneau léger, les Panneaux de contrôle VPS offrent plusieurs alternatives adaptées à différents flux de travail opérationnels.

Pour les projets qui nécessitent également une transmission sécurisée des données, associer votre migration de base de données à un Certificat SSL correctement configuré garantit que les données encodées en utf8mb4 sont protégées en transit, et pas seulement au repos.

Liste de contrôle des décisions techniques

Utilisez cette liste de contrôle avant et après toute migration d’utf8 vers utf8mb4 :

Avant la migration :

  • [ ] Sauvegarde `mysqldump` complète vérifiée et restaurable
  • [ ] Version MySQL confirmée (5.5.3+ requise pour utf8mb4)
  • [ ] Statut `innodb_large_prefix` vérifié (activer si sur MySQL 5.6/5.7)
  • [ ] Toutes les colonnes `VARCHAR(255)` avec des index sur colonne complète identifiées
  • [ ] Code du jeu de caractères de connexion de l’application revu et mis à jour
  • [ ] Fenêtre de maintenance planifiée pour les bases de données de production

Après la migration :

  • [ ] `SHOW VARIABLES LIKE 'character_set%'` affiche `utf8mb4` au niveau du serveur
  • [ ] `SHOW CREATE TABLE` confirme `utf8mb4` sur toutes les tables converties
  • [ ] La requête `information_schema.COLUMNS` confirme l’absence de colonnes `utf8` restantes
  • [ ] `SET NAMES utf8mb4` au niveau de l’application ou équivalent confirmé dans le code de connexion
  • [ ] Test d’insertion d’emoji réussi sur une table représentative
  • [ ] Référence de performance des requêtes comparée aux métriques d’avant la migration
  • [ ] Longueurs d’index vérifiées — aucune troncature silencieuse des valeurs indexées longues

FAQ

La migration d’utf8 vers utf8mb4 entraîne-t-elle une perte de données ?

Non. utf8mb4 est un sur-ensemble strict de l’utf8 de MySQL. Chaque caractère stocké dans une colonne utf8 est identiquement représentable dans utf8mb4. La migration est non destructive pour les données existantes. Le seul risque concerne les erreurs de longueur d’index sur les colonnes `VARCHAR(255)` avec des index sur colonne complète, qui doivent être résolues en raccourcissant le préfixe d’index.

Pourquoi les emoji échouent-ils encore à être insérés après avoir converti mes tables en utf8mb4 ?

La cause la plus courante est le jeu de caractères de connexion de l’application. Si votre code PHP, Python ou Node.js se connecte sans spécifier explicitement `utf8mb4`, MySQL utilise le défaut `character_set_client` du serveur pour cette session. Ajoutez `SET NAMES utf8mb4` ou le paramètre de jeu de caractères équivalent à votre configuration de connexion.

Quelle est la différence entre utf8mb4_unicode_ci et utf8mb4_0900_ai_ci ?

`utf8mb4_unicode_ci` est basée sur les règles de collation Unicode 4.0 et est le choix standard pour MySQL 5.7. `utf8mb4_0900_ai_ci` est basée sur Unicode 9.0, est le défaut dans MySQL 8.0, et est à la fois plus rapide et plus précise linguistiquement. Utilisez `utf8mb4_0900_ai_ci` sur MySQL 8.0+ pour les nouveaux projets.

Le passage à utf8mb4 augmentera-t-il significativement la taille de ma base de données ?

En pratique, non. Les caractères ASCII et la plupart des caractères BMP utilisent le même nombre d’octets dans les deux encodages. Seuls les caractères supplémentaires (emoji, CJK supplémentaire) utilisent 4 octets — et ceux-ci étaient non représentables dans utf8 auparavant. La surcharge mémoire pour les tampons de tri augmente d’environ 33 % pour les opérations intensives en chaînes, mais cela est négligeable sur tout serveur moderne.

Puis-je configurer utf8mb4 sur un hébergement partagé ?

Partiellement. Vous pouvez définir le jeu de caractères au niveau de la base de données et de la table en utilisant des instructions SQL `ALTER`, et vous pouvez spécifier le jeu de caractères dans la chaîne de connexion de votre application. Cependant, vous ne pouvez pas modifier `my.cnf` ni redémarrer MySQL sur un hébergement partagé. Les défauts au niveau du serveur resteront inchangés, ce qui signifie que les nouvelles bases de données créées via le panneau d’hébergement peuvent utiliser utf8 par défaut. Une configuration complète d’utf8mb4 nécessite un VPS ou un serveur dédié avec accès root.

15%

Économisez 15% sur tous les services d'hébergement

Testez vos compétences et obtenez Réduction sur tout plan d'hébergement

Utilisez le code :

Skills
Commencer