15%

Economisește 15% la toate serviciile de găzduire

Testează-ți abilitățile și obține Reducere la orice plan de găzduire

Utilizați codul:

Skills
Începeți
08.10.2024

utf8 vs utf8mb4 în MySQL: Ghidul Tehnic Complet

Setul de caractere utf8 al MySQL este un termen impropriu — nu este o implementare UTF-8 adevărată. Codifică caracterele folosind doar 1 până la 3 octeți, ceea ce înseamnă că elimină sau respinge silențios orice punct de cod Unicode peste U+FFFF, inclusiv toate emoji-urile și o parte semnificativă a caracterelor CJK suplimentare. utf8mb4 este implementarea UTF-8 corectă și completă a MySQL, suportând 1 până la 4 octeți per caracter și întreaga gamă Unicode. Pentru orice bază de date de producție construită după 2010, utf8mb4 este singura alegere justificabilă.

Acest ghid explică exact de ce contează această distincție, unde a greșit designul original utf8, cum să migrați în siguranță și cum să configurați MySQL corect la nivelul serverului, bazei de date, tabelului și conexiunii.

Problema de bază: De ce utf8 al MySQL este defect prin design

Standardul de codificare UTF-8 (RFC 3629) definește o schemă cu lățime variabilă care folosește 1 până la 4 octeți pentru a reprezenta fiecare punct de cod Unicode valid — peste 1,1 milioane de caractere posibile. Când MySQL și-a introdus setul de caractere `utf8` în versiunea 4.1, implementarea a fost limitată intenționat la 3 octeți per caracter. Aceasta a fost o scurtătură de inginerie deliberată, nu o omisiune.

La acea vreme, formatul de rând InnoDB impunea o limită de 767 de octeți pentru prefixele cheilor de index. Suportarea caracterelor de 4 octeți ar fi redus lungimea maximă a prefixului indexat pentru coloanele `VARCHAR`, creând probleme de compatibilitate a indexurilor. Limita de 3 octeți a fost o soluție pragmatică care a devenit o responsabilitate pe termen lung.

Consecința practică: orice punct de cod Unicode din Planul Multilingv Suplimentar (SMP) — puncte de cod U+10000 și mai sus — nu poate fi stocat într-o coloană `utf8`. Aceasta include:

  • Toate emoji-urile standard (U+1F600 și mai departe)
  • Simboluri alfanumerice matematice (U+1D400–U+1D7FF)
  • Simboluri de notație muzicală
  • Scripturi istorice precum Linear B, Gothic și Cuneiform
  • Ideograme CJK Unificate Suplimentare (U+20000–U+2A6DF)
  • Anumite simboluri valutare și operatori tehnici adăugați în versiunile recente Unicode

Când o aplicație încearcă să insereze un caracter de 4 octeți într-o coloană `utf8`, MySQL fie returnează o eroare `Incorrect string value`, fie, dacă `sql_mode` este permisiv, trunchiază silențios datele. Trunchierea silențioasă este probabil rezultatul mai periculos — aplicația dvs. nu primește nicio eroare, dar datele sunt corupte.

utf8mb4: Implementarea corectă

MySQL a introdus utf8mb4 în versiunea 5.5.3 (lansată în 2010) special pentru a remedia această deficiență. Sufixul `mb4` înseamnă „multi-byte, maximum 4 octeți”. Este un superset strict al `utf8` — fiecare caracter reprezentabil în `utf8` este identic reprezentabil în `utf8mb4`. Nu există pierdere de date la migrarea de la `utf8` la `utf8mb4`.

utf8mb4 se mapează direct la standardul UTF-8 RFC 3629. Gestionează întregul spațiu de coduri Unicode de la U+0000 la U+10FFFF fără restricții.

utf8 vs utf8mb4: Comparație de caracteristici

Caracteristicăutf8 (MySQL)utf8mb4
Octeți per caracter1–31–4
Acoperire UnicodeDoar BMP (U+0000–U+FFFF)Completă (U+0000–U+10FFFF)
Suport emojiNuDa
CJK suplimentarNuDa
Conform RFC 3629NuDa
Prefix maxim index (InnoDB, pagini 4KB)767 octeți767 octeți (191 caractere)
Prefix maxim index (innodb_large_prefix)3072 octeți3072 octeți (768 caractere)
Overhead stocare față de latin1Identic pentru ASCIIIdentic pentru ASCII
Recomandat pentru proiecte noiNuDa
Versiunea MySQL introdusă4.15.5.3

Alegeri de colație în utf8mb4

Selectarea utf8mb4 ca set de caractere reprezintă doar jumătate din decizie. Colația determină modul în care șirurile sunt comparate, sortate și indexate. Colația greșită cauzează comportamente de interogare subtile, greu de depanat.

utf8mb4_unicode_ci

Bazată pe Algoritmul de Colație Unicode (UCA). Gestionează corect regulile de sortare specifice limbii. Ușor mai lentă decât `utf8mb4_general_ci` datorită logicii de comparație mai complexe, dar diferența de performanță este neglijabilă pe hardware modern.

utf8mb4_general_ci

O colație simplificată care nu implementează complet UCA. Mai rapidă în benchmark-urile din începutul anilor 2010, dar avantajul de viteză este irelevant pe CPU-urile actuale. Gestionează incorect unele cazuri limită — de exemplu, tratează anumite caractere germane ca echivalente când nu ar trebui. Evitați pentru proiecte noi.

utf8mb4_0900_ai_ci

Disponibilă în MySQL 8.0+. Bazată pe Unicode 9.0 cu comparație insensibilă la accente (`ai`) și insensibilă la majuscule (`ci`). Aceasta este valoarea implicită recomandată pentru MySQL 8.0 și versiunile ulterioare. Este mai rapidă decât `utf8mb4_unicode_ci` și mai precisă.

utf8mb4_bin

Comparație binară — sensibilă la majuscule, sensibilă la accente, fără reguli specifice localizării. Utilizați când aveți nevoie de potrivire exactă la nivel de octet, cum ar fi pentru hash-uri de parole sau identificatori sensibili la majuscule.

Recomandare: Utilizați `utf8mb4_0900_ai_ci` pe MySQL 8.0+. Utilizați `utf8mb4_unicode_ci` pe MySQL 5.7 și versiunile anterioare.

Implicații de stocare și index

O preocupare comună la migrarea de la utf8 la utf8mb4 este overhead-ul de stocare. În practică, impactul este minim:

  • Caracterele ASCII (U+0000–U+007F) ocupă în continuare exact 1 octet în ambele codificări.
  • Majoritatea caracterelor latine, grecești, chirilice, arabe și ebraice ocupă 2 octeți în ambele codificări.
  • Caracterele CJK din BMP ocupă 3 octeți în ambele codificări.
  • Doar caracterele suplimentare (emoji, CJK suplimentar) necesită 4 octeți — și acestea erau pur și simplu nereprezentabile în utf8 înainte.

Preocuparea reală legată de index este limita de prefix index InnoDB de 767 de octeți pe configurațiile mai vechi. Cu utf8mb4, un caz cel mai defavorabil de 4 octeți per caracter înseamnă că un prefix de index `VARCHAR` de 191 de caractere atinge plafonul de 767 de octeți. Cu `utf8`, același plafon permitea 255 de caractere. Dacă aveți coloane `VARCHAR(255)` cu indexuri pe coloana completă, puteți întâlni erori `Specified key was too long` în timpul migrării.

Soluții:

  • Activați `innodb_large_prefix = ON` (MySQL 5.6/5.7) pentru a ridica limita la 3072 de octeți.
  • Utilizați `ROW_FORMAT=DYNAMIC` sau `ROW_FORMAT=COMPRESSED` pe tabelele afectate.
  • În MySQL 8.0, `innodb_large_prefix` este activat implicit și parametrul este eliminat.
  • Scurtați prefixele de index: `INDEX (column(191))` în loc de `INDEX (column(255))`.

Acesta este cel mai frecvent punct de eșec al migrării și cel mai frecvent subdocumentat în ghidurile de bază.

Cum să migrați o bază de date MySQL de la utf8 la utf8mb4

Migrarea este simplă, dar necesită precizie. Omiterea oricărui nivel — server, bază de date, tabel sau conexiune — lasă aplicația să revină silențios la codificarea veche.

Pasul 1: Faceți backup la baza de date

Nu modificați niciodată codificarea caracterelor pe o bază de date live fără un backup verificat.

“`bash

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

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

“`

Indicatorul `–single-transaction` asigură un snapshot consistent pentru tabelele InnoDB fără blocare. Stocați backup-ul într-o locație separată de serverul bazei de date înainte de a continua.

Pasul 2: Actualizați configurația serverului MySQL

Editați `/etc/mysql/my.cnf` sau `/etc/mysql/mysql.conf.d/mysqld.cnf` în funcție de distribuția dvs.:

“`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

“`

Reporniți MySQL:

“`bash

sudo systemctl restart mysql

“`

Pasul 3: Convertiți baza de date

“`sql

ALTER DATABASE database_name

CHARACTER SET = utf8mb4

COLLATE = utf8mb4_unicode_ci;

“`

Pasul 4: Convertiți toate tabelele

Generați și executați instrucțiuni `ALTER TABLE` pentru fiecare tabel. Rularea lor manuală pe scheme mari este predispusă la erori. Utilizați această interogare pentru a genera instrucțiunile automat:

“`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';

“`

Executați fiecare instrucțiune generată. Sintaxa `CONVERT TO CHARACTER SET` modifică atât valoarea implicită a tabelului, cât și toate coloanele de caractere existente într-o singură operație.

Pasul 5: Remediați erorile de lungime a indexului

Dacă întâlniți `Specified key was too long; max key length is 767 bytes`, identificați indexul problematic:

“`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));

“`

Pentru bazele de date WordPress în special, coloana `option_name` a tabelului `wp_options` și coloana `meta_key` a `wp_postmeta` sunt surse frecvente ale acestei erori.

Pasul 6: Verificați conversia

“`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');

“`

Fiecare valoare `CHARACTER_SET_NAME` ar trebui să citească `utf8mb4`.

Pasul 7: Actualizați șirurile de conexiune ale aplicației

Codificarea serverului și a schemei nu înseamnă nimic dacă aplicația dvs. se conectează folosind setul de caractere greșit. Codificarea la nivel de conexiune suprascrie valoarea implicită a serverului.

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'

});

“`

Nesetarea charset-ului conexiunii este cel mai frecvent motiv pentru care emoji-urile continuă să nu se insereze după o migrare presupus completă.

Considerații specifice WordPress

WordPress a livrat utf8mb4 ca set de caractere implicit începând cu versiunea 4.2 (aprilie 2015). Dacă rulați o instalare WordPress pe o bază de date mai veche care nu a fost niciodată migrată, fișierul `wp-config.php` poate conține în continuare:

“`php

define('DB_CHARSET', 'utf8');

“`

Schimbați aceasta în:

“`php

define('DB_CHARSET', 'utf8mb4');

define('DB_COLLATE', 'utf8mb4_unicode_ci');

“`

WordPress include, de asemenea, o rutină de upgrade încorporată (`maybe_convert_table_to_utf8mb4()`) care rulează în timpul actualizărilor de bază. Cu toate acestea, această rutină nu prinde întotdeauna fiecare tabel, în special cele create de plugin-uri. Rularea abordării manuale `ALTER TABLE` descrisă mai sus este mai fiabilă.

Într-un mediu de VPS Hosting cu acces root, puteți automatiza întregul acest proces cu un script shell și îl puteți programa ca un job cron unic, oferindu-vă control complet asupra timpului și jurnalizării.

Considerații de performanță

Impactul de performanță al utf8mb4 față de utf8 este neglijabil pentru marea majoritate a sarcinilor de lucru:

  • Interogări de citire: Nicio diferență măsurabilă pentru caracterele BMP. Caracterele suplimentare necesită un octet suplimentar de I/O, care este absorbit de memoria cache a pool-ului de buffere.
  • Interogări de scriere: Identice pentru conținut ASCII și BMP. Marginal mai mari pentru caracterele suplimentare.
  • Operații de index: Lungimea maximă redusă a prefixului (191 față de 255 de caractere pentru indexuri pe lățime completă) poate afecta planurile de interogare dacă aveți indexuri pe coloana completă pe coloane `VARCHAR` lungi. Auditați indexurile înainte și după migrare.
  • Memorie: MySQL alocă buffere cu lățime fixă pentru operațiile cu șiruri bazate pe numărul maxim de octeți per caracter. Trecerea de la utf8 (max 3 octeți) la utf8mb4 (max 4 octeți) crește memoria alocată pentru bufferele de sortare în memorie și tabelele temporare cu aproximativ 33% pentru operațiile intensive cu șiruri. Pe un Server Dedicat cu RAM suficient, acest lucru este neconsequent. Într-un mediu partajat cu memorie limitată, monitorizați `sort_buffer_size` și `tmp_table_size` după migrare.

Când utf8 este încă acceptabil

Există un set restrâns de motive legitime pentru a păstra `utf8`:

  • Compatibilitate strictă cu sisteme vechi: O aplicație care utilizează un ORM neîntreținut sau un driver de bază de date care nu poate gestiona caractere de 4 octeți. Aceasta este o problemă de datorie tehnică, nu un motiv pentru a păstra utf8 pe termen nelimitat.
  • Baze de date de arhivare doar pentru citire: Dacă o bază de date nu va primi niciodată scrieri noi și datele existente nu conțin caractere suplimentare, migrarea adaugă risc fără niciun beneficiu.
  • Constrângeri stricte de stocare: În cazuri extreme — sisteme încorporate sau medii cu capacitate sever limitată — diferența marginală de stocare ar putea conta. Aceasta nu se aplică niciunui scenariu standard de web hosting.

În orice alt caz, utf8mb4 este alegerea corectă. Argumentul că utf8 economisește spațiu de stocare este tehnic adevărat doar pentru caracterele suplimentare, care erau oricum nereprezentabile în utf8. Nu economisiți spațiu pe date pe care nu le puteați stoca.

Alegerea mediului de hosting potrivit pentru MySQL utf8mb4

Configurarea corectă a utf8mb4 necesită acces la fișierul de configurare al serverului MySQL (`my.cnf`). Aceasta exclude majoritatea mediilor de hosting partajat unde nu puteți modifica variabilele la nivel de server.

Pentru control complet asupra codificării caracterelor MySQL, colației, setărilor InnoDB și parametrilor de conexiune, aveți nevoie fie de un plan de VPS Hosting cu acces root, fie de un Server Dedicat. Ambele vă oferă acces direct la `/etc/mysql/my.cnf`, capacitatea de a reporni serviciul MySQL și libertatea de a configura `innodb_large_prefix`, `ROW_FORMAT` și alți parametri care afectează succesul migrării utf8mb4.

Dacă gestionați mai multe baze de date sau site-uri ale clienților, un VPS cu cPanel oferă o interfață grafică pentru gestionarea bazelor de date, păstrând în același timp accesul la serverul de bază necesar pentru configurarea setului de caractere. Pentru echipele care preferă flexibilitatea liniei de comandă cu un panou ușor, Panourile de Control VPS oferă mai multe alternative potrivite pentru diferite fluxuri de lucru operaționale.

Pentru proiectele care necesită, de asemenea, transmiterea securizată a datelor, asocierea migrării bazei de date cu un Certificat SSL configurat corespunzător asigură că datele codificate utf8mb4 sunt protejate în tranzit, nu doar în repaus.

Listă de verificare pentru decizii tehnice

Utilizați această listă de verificare înainte și după orice migrare de la utf8 la utf8mb4:

Pre-migrare:

  • [ ] Backup `mysqldump` complet verificat și restaurabil
  • [ ] Versiunea MySQL confirmată (5.5.3+ necesară pentru utf8mb4)
  • [ ] Starea `innodb_large_prefix` verificată (activați dacă folosiți MySQL 5.6/5.7)
  • [ ] Toate coloanele `VARCHAR(255)` cu indexuri pe coloana completă identificate
  • [ ] Codul charset al conexiunii aplicației revizuit și actualizat
  • [ ] Fereastră de mentenanță programată pentru bazele de date de producție

Post-migrare:

  • [ ] `SHOW VARIABLES LIKE 'character_set%'` arată `utf8mb4` la nivel de server
  • [ ] `SHOW CREATE TABLE` confirmă `utf8mb4` pe toate tabelele convertite
  • [ ] Interogarea `information_schema.COLUMNS` confirmă că nu mai există coloane `utf8`
  • [ ] `SET NAMES utf8mb4` la nivel de aplicație sau echivalentul confirmat în codul de conexiune
  • [ ] Testul de inserare emoji trecut pe un tabel reprezentativ
  • [ ] Linia de bază a performanței interogărilor comparată cu metricile pre-migrare
  • [ ] Lungimile indexurilor verificate — nicio trunchiare silențioasă a valorilor indexate lungi

Întrebări frecvente

Migrarea de la utf8 la utf8mb4 cauzează pierderi de date?

Nu. utf8mb4 este un superset strict al utf8 al MySQL. Fiecare caracter stocat într-o coloană utf8 este identic reprezentabil în utf8mb4. Migrarea este nedestructivă pentru datele existente. Singurul risc sunt erorile de lungime a indexului pe coloanele `VARCHAR(255)` cu indexuri pe coloana completă, care trebuie rezolvate prin scurtarea prefixului de index.

De ce emoji-urile continuă să nu se insereze după ce am convertit tabelele la utf8mb4?

Cea mai frecventă cauză este charset-ul conexiunii aplicației. Dacă codul dvs. PHP, Python sau Node.js se conectează fără a specifica explicit `utf8mb4`, MySQL folosește valoarea implicită `character_set_client` a serverului pentru acea sesiune. Adăugați `SET NAMES utf8mb4` sau parametrul charset echivalent în configurația conexiunii dvs.

Care este diferența dintre utf8mb4_unicode_ci și utf8mb4_0900_ai_ci?

`utf8mb4_unicode_ci` este bazată pe regulile de colație Unicode 4.0 și este alegerea standard pentru MySQL 5.7. `utf8mb4_0900_ai_ci` este bazată pe Unicode 9.0, este valoarea implicită în MySQL 8.0 și este atât mai rapidă, cât și mai precisă lingvistic. Utilizați `utf8mb4_0900_ai_ci` pe MySQL 8.0+ pentru proiecte noi.

Trecerea la utf8mb4 va crește semnificativ dimensiunea bazei mele de date?

În practică, nu. Caracterele ASCII și majoritatea caracterelor BMP folosesc același număr de octeți în ambele codificări. Doar caracterele suplimentare (emoji, CJK suplimentar) folosesc 4 octeți — și acestea erau nereprezentabile în utf8 înainte. Overhead-ul de memorie pentru bufferele de sortare crește cu aproximativ 33% pentru operațiile intensive cu șiruri, dar acest lucru este neglijabil pe orice server modern.

Pot configura utf8mb4 pe hosting partajat?

Parțial. Puteți seta setul de caractere la nivel de bază de date și tabel folosind instrucțiuni SQL `ALTER`, și puteți specifica charset-ul în șirul de conexiune al aplicației dvs. Cu toate acestea, nu puteți modifica `my.cnf` sau reporni MySQL pe hosting partajat. Valorile implicite la nivel de server vor rămâne neschimbate, ceea ce înseamnă că noile baze de date create prin panoul de hosting pot implicit la utf8. Configurarea completă utf8mb4 necesită un VPS sau server dedicat cu acces root.

15%

Economisește 15% la toate serviciile de găzduire

Testează-ți abilitățile și obține Reducere la orice plan de găzduire

Utilizați codul:

Skills
Începeți