При переходе с 5й версии mysql на 8ю, при тестировании могут возникать проблемы с базой данных. Часть из них успешно исправит сам битрикс или предложит варианты решения, например прописать определенные параметры в конфигурационные файлы. Но часть проблем останутся нерешенными.
Одна из таких ошибок при тестировании:
Ошибка! Кодировки таблиц имеют ошибки, общее число ошибок: 987, из них автоматически могут быть исправлены: 0.
Тут нам битрикс предлагает заглянуть поглубже, а точнее в журнал проверки системы. И там открывается ужасная картина:
Кодировка таблицы "b_b24connector_button_site" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "SITE_ID" таблицы "b_b24connector_button_site" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "PERSON_TYPE" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "PERSON_NAME" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "PERSON_LASTNAME" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "PERSON_MIDDLENAME" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "EMAIL" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "PHONE" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "POST_INDEX" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "COUNTRY" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "CITY" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "COMPANY" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "INN" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "KPP" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "ADDRESS" таблицы "b_catalog_contractor" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка таблицы "b_catalog_currency" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "CURRENCY" таблицы "b_catalog_currency" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "NUMCODE" таблицы "b_catalog_currency" (utf8mb4) отличается от кодировки базы (utf8mb3) Кодировка поля "BASE" таблицы "b_catalog_currency" (utf8mb4) отличается от кодировки базы (utf8mb3)
Но, если разбираться более конкретно, то на самом деле, тут нет ничего страшного. Проблема лишь в том, что в базе используется кодировка utf8mb3
, а битрикс ожидает увидеть кодировку utf8mb4
. Тут следует углубится в теорию и понять, чем же отличаются utf8mb3
и utf8mb4
На самом деле, данная ошибка практически ни на что не влияет, и по идее битрикс должен был пропустить мимо, но что есть, то есть. Различия в этих кодировках минимальны, самое главное, что это все то же utf8
:
- utf8mb3
поддерживает только символы в Basic Multilingual Plane (BMP), то-есть выделяет 3 байта на символ, что вполне хватает для символов практически всех языков, но не может работать с более длинными символами. Это эмодзи(emoji) и сложные иероглифы.
- utf8mb4
поддерживает до 4х байтов на символ, что закрывает недостатки utf8mb3
.
Соответственно, в новых проектах, следует хранить данные в utf8mb4
, что битрикс и прописывает в своих sql картах. Но, что же делать нам с такой ошибкой? Самое главное - это сделать бекап базы данных. А дальше меняем кодировку БД. Для этого переходим в Настройки -> Инструменты -> SQL запрос и выполняем:
ALTER DATABASE `имя_вашей_базы` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
Теперь Ваша база работает в современной кодировке, но надо об этом сообщить же и битриксу. Переходим в /bitrix/php_interface/after_connect.php и заменяем:
$DB->Query("SET NAMES 'utf8'");
$DB->Query('SET collation_connection = "utf8_unicode_ci"');
на:
$DB->Query("SET NAMES 'utf8mb4'");
$DB->Query('SET collation_connection = "utf8mb4_general_ci"');
Похожую процедуру производим и в /bitrix/php_interface/after_connect_d7.php:
$this->queryExecute("SET NAMES 'utf8");
$this->queryExecute('SET collation_connection = "utf8_unicode_ci"');
Меняем на
$this->queryExecute("SET NAMES 'utf8mb4'");
$this->queryExecute('SET collation_connection = "utf8mb4_general_ci"');
Заметьте, что тут используется конструкция $this->queryExecute, но до версии 22.0.0 использовалась конструкция:
$connection = \Bitrix\Main\Application::getConnection();
$connection->queryExecute('SET NAMES "utf8"');
$connection->queryExecute('SET collation_connection = "utf8_unicode_ci"');
Снова тестируем систему. Могут возникнуть ошибки, которые битрикс исправит автоматически. Исправляем и снова тестируем. И получаем ошибку:
Ошибка! Кодировки таблиц имеют ошибки, общее число ошибок: 1640, из них автоматически могут быть исправлены: 0..
Открываем журнал и видим примерно тоже самое:
Кодировка таблицы "b_admin_notify" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "MODULE_ID" таблицы "b_admin_notify" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "TAG" таблицы "b_admin_notify" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "MESSAGE" таблицы "b_admin_notify" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "ENABLE_CLOSE" таблицы "b_admin_notify" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "PUBLIC_SECTION" таблицы "b_admin_notify" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "NOTIFY_TYPE" таблицы "b_admin_notify" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка таблицы "b_admin_notify_lang" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "LID" таблицы "b_admin_notify_lang" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "MESSAGE" таблицы "b_admin_notify_lang" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка таблицы "b_agent" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "MODULE_ID" таблицы "b_agent" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "NAME" таблицы "b_agent" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "ACTIVE" таблицы "b_agent" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "IS_PERIOD" таблицы "b_agent" (utf8mb3) отличается от кодировки базы (utf8mb4) Кодировка поля "RUNNING" таблицы "b_agent" (utf8mb3) отличается от кодировки базы (utf8mb4)
Теперь нам надо делать все самим. Снова нужно сформировать запрос, который изменит кодировку конкретной таблицы:
ALTER TABLE `b_admin_notify` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
То-есть находим все записи о неверной кодировки таблицы и формируем запросы. После чего выполняем их и запускаем проверку системы снова. После чего могут появится новые проблемы с полями в журнале:
ALTER TABLE `b_messageservice_channel` CHANGE `ADDITIONAL_PARAMS` `ADDITIONAL_PARAMS` text NULL DEFAULT NULL; ALTER TABLE `b_ticket` MODIFY `TITLE` varchar(255) NOT NULL ;
Ошибки такого вида - это запросы, которые мы просто выполняем в Настройки -> Инструменты -> SQL запрос
Вариативность ошибок может быть разная, например:
В таблице b_iblock поле DESCRIPTION "`DESCRIPTION` mediumtext NULL DEFAULT NULL" не соответствует описанию на диске "`DESCRIPTION` text NULL DEFAULT NULL"
Подобные ошибки лечатся преобразованием в запрос вида:
ALTER TABLE `b_iblock` CHANGE `DESCRIPTION` `DESCRIPTION` text NULL DEFAULT NULL;
После всех преобразований, тестируем систему, ошибок быть не должно. Далее необходимо оптимизировать БД. Переходим в Настройки -> Инструменты -> Диагностика -> Оптимизация БД и выполняем оптимизацию. На этом - все.
Ну и на последок, для тех кому лень руками прописывать все запросы, можно скопировать их из журнала в какой нибудь файл, например в convert_db.txt
, рядом положить файл convert_db.php
и написать простейший скриптик, который перобразует текст ошибок в SQL запросы, например:
$lines = file('convert_db.txt', FILE_IGNORE_NEW_LINES);
foreach($lines as $line){
if (str_contains($line, 'Кодировка таблицы')) {
echo preg_replace("!Кодировка таблицы \"(.*?)\" \((.*?)\) отличается от кодировки базы \((.*?)\)!si","ALTER TABLE \\1 CONVERT TO CHARACTER SET \\3 COLLATE \\3_general_ci;",$line);
echo "<\br>";
}elseif(str_contains($line, 'В таблице')){
echo preg_replace("!В таблице (.*?) поле (.*?) \"(.*?)\" не соответствует описанию на диске \"(.*?)\"!si","ALTER TABLE `\\1` CHANGE `\\2` \\4;",$line);
echo "<\br>";
}
}
В итоге, вместо:
В таблице b_iblock поле DESCRIPTION "`DESCRIPTION` mediumtext NULL DEFAULT NULL" не соответствует описанию на диске "`DESCRIPTION` text NULL DEFAULT NULL" Кодировка таблицы "b_admin_notify_lang" (utf8mb3) отличается от кодировки базы (utf8mb4)
Вы получите:
ALTER TABLE `b_iblock` CHANGE `DESCRIPTION` `DESCRIPTION` text NULL DEFAULT NULL;
ALTER TABLE b_admin_notify_lang CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;