Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чому utf8 у MySQL - це не повний UTF-8 і як перевести таблиці на utf8mb4?

Історично utf8 у MySQL - це utf8mb3: до 3 байтів на символ. Справжній UTF-8 використовує до 4 байтів, і 4-байтові символи (емодзі, частина ієрогліфів, математичні символи) в utf8mb3 не вміщуються.

Що відбувається на практиці: користувач пише коментар з емодзі, і вставка падає з Incorrect string value: '\xF0\x9F\x98\x80', а в нестрогому режимі - текст обрізається на першому емодзі без помилки.

utf8mb4 - повний UTF-8. У MySQL 8 це кодування за замовчуванням (з collation utf8mb4_0900_ai_ci), а utf8mb3 застаріло.

Переведення наявних таблиць:

ALTER DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

ALTER TABLE comments CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

CONVERT TO перекодовує дані всіх текстових колонок - це перебудова таблиці: на великих таблицях довго, з блокуванням запису. Для продакшену - через gh-ost чи pt-online-schema-change.

Підводні камені переходу:

  • Ліміт довжини ключа індексу. У старих версіях і форматах рядка (COMPACT) ключ обмежений 767 байтами: VARCHAR(255) в utf8mb4 - це 1020 байтів, і індекс не створюється. Звідси Schema::defaultStringLength(191) у старих Laravel-проєктах. З форматом DYNAMIC (за замовчуванням у MySQL 8) ліміт - 3072 байти, і проблеми немає.
  • Зміна collation змінює порівняння: нечутливість до регістру й діакритики (ai_ci) може зробити «різні» значення однаковими - і унікальний індекс не створиться, поки дублікати не прибрати.
  • Розмір: тексти, що містять 4-байтові символи, займуть більше; для кирилиці розмір не зміниться (2 байти на символ).
  • З'єднання теж має бути utf8mb4: charset у конфігурації підключення ('charset' => 'utf8mb4' у Laravel) - інакше дані перекодуються в utf8mb3 ще по дорозі.

Правило для нових проєктів: лише utf8mb4 скрізь - сервер, база, таблиці, з'єднання.

Докладніше в документації: Кодування utf8mb4

1

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання