Спор о том, какую ветку ставить на сервер, тянется с тех пор, как Oracle купила Sun Microsystems, а создатель MySQL ушёл строить форк. За полтора десятилетия обе СУБД отдалились друг от друга: появились разные движки хранения, разные умолчания аутентификации, разные форматы журналов репликации. Для администратора вопрос стоит практично: что даёт конкретному проекту каждая ветка и как перевезти готовую базу с MySQL на MariaDB или обратно, не потеряв ни строки и не уронив продакшен на ночь. Ниже сравнение по функциям, разбор ловушек совместимости и рабочая схема переезда в обе стороны с командами, которые копируются в терминал без правок.
Разные дороги MariaDB и MySQL после разделения кодовой базы
Короткая родословная. MySQL досталась Sun Microsystems в 2008 году, а в 2010-м вместе с Sun перешла под контроль Oracle. Автор оригинала Михаэль Видениус в ответ открыл форк и назвал его в честь младшей дочери Марии. Первые годы MariaDB тянулась за старшей веткой как замена без единой правки кода, сегодня о прямой замене уже не говорят.
Маршруты разошлись после MySQL 5.7. Oracle в 2018 году выпустила MySQL 8.0 с полностью переписанным словарём данных, затем перешла на двухколейную модель: LTS-ветка 8.4, консервативная 8.0.x и короткие инновационные серии 9.x. По свежим выпускам в зеркале исходников инновационная линейка дошла до 9.7.2, долгосрочная 8.4 доросла до 8.4.11, а ветеран 8.0.x получает правки вплоть до 8.0.46. MariaDB живёт собственной нумерацией: свежая стабильная серия имеет номер 13.0, следом релиз-кандидат 13.1 и предпросмотр 13.2, а статус долгосрочных закреплён за сериями 12.3, 11.8 и 11.4. Почтенная 10.11 живёт до февраля 2028, а легендарная 10.6 доживает до июля 2026.
Лицензии у обеих открытые, на GPL версии 2, но акценты разные. У MariaDB открыт и сервер, и штатный кластерный плагин Galera, и утилита горячего резервного копирования mariadb-backup; лишь балансировщик MaxScale живёт по отдельной лицензии BSL. У Oracle открыт Community-сервер, однако пул потоков, расширения аудита и корпоративный бэкап продаются с подпиской Enterprise.
Наивно считать одну ветку "настоящей", а вторую "подделкой": это два зрелых продукта с разными хозяевами и разными сильными сторонами. Дальше обе разобраны без рекламных чувств, глазами админа с задачами на вечер.
Сравнение возможностей MariaDB и MySQL в задачах реальных проектов
Ядро возможностей у веток давно совпадает: табличные выражения CTE, оконные функции, строгие CHECK-ограничения, невидимые индексы, мгновенное добавление колонок без пересборки таблицы. Типичному сайту на популярной CMS всё равно, что стоит под капотом. Различия вылезают на краях, и именно края определяют выбор.
Козыри MariaDB. Последовательности CREATE SEQUENCE выдают номера без таблицы-счётчика. Системные таблицы с конструкцией WITH SYSTEM VERSIONING хранят историю строк прямо в таблице, старые версии доступны запросом по времени. Синтаксис RETURNING возвращает изменённые строки без второго запроса. Кластер Galera ставится штатным плагином wsrep и синхронно реплицирует данные между узлами. Внутри есть движок Aria для временных таблиц, колоночный ColumnStore и экзотика вроде CONNECT и Spider. Горячее резервное копирование делает штатный mariadb-backup.
Козыри MySQL. Настоящий тип JSON: колонки хранятся в компактном бинарном формате, валидируются при записи и разбираются быстрее, тогда как в MariaDB JSON остаётся текстовым LONGTEXT с контрольной функцией. Правила сравнения семейства utf8mb4_0900_ai_ci на основе Unicode 9.0 дают аккуратную сортировку для десятков языков, у MariaDB таких нет. Связка InnoDB Cluster из групповой репликации, роутера и MySQL Shell собирает отказоустойчивый кластер из коробки, а ускоритель HeatWave добавляет аналитику поверх данных.
Вывод скучен и полезен: магазин, блог или корпоративный портал одинаково живут на обеих ветках, решают частные потребности. Если проекту нужны таблицы с историей, последовательности, встроенный кластер и бесплатные инструменты эксплуатации, взгляд уходит в сторону MariaDB. Если нужен бинарный JSON, строгая сортировка по Unicode и экосистема Oracle, выбор падает на MySQL.
Ловушки совместимости, которые всплывают при первом импорте дампа
Совместимость между ветками хорошая, но не стерильная. Практика переездов показывает, что импорт дампа чаще всего обрывается на пяти вещах:
1. правило сравнения utf8mb4_0900_ai_ci, которого в MariaDB нет;
2. учётные записи с плагином аутентификации caching_sha2_password;
3. функциональные части индекса из MySQL 8, которые MariaDB не разбирает;
4. прямые ссылки на служебную схему mysql в коде приложений и процедурах;
5. репликация с GTID, у которой у веток принципиально разный формат.
Правило сравнения лечится одной строкой sed, о ней ниже. Плагин caching_sha2_password в MariaDB отсутствует, поэтому учётные записи создают заново либо заранее переводят в mysql_native_password на старом сервере, если его версия это ещё позволяет. Функциональные части индекса вида INDEX idx ((LOWER(email))) переписывают через вычислимый столбец и обычный индекс по нему. Ссылки на служебную схему ищут по коду заранее: их любят мониторинг и скрипты отчётов. GTID у MySQL выглядит как UUID с номером транзакции, у MariaDB как тройка "домен-сервер-номер", сквозная репликация между свежими ветками официально не поддерживается.
Вне списка живут мягкие различия: умолчания sql_mode у веток разные, MySQL строже к запросам с GROUP BY, а часовые пояса сверяют до переключения, чтобы отчёты не поехали по времени.
И ещё одно обстоятельство: физически копировать файлы между ветками нельзя, у MySQL словарь данных хранится внутри InnoDB, у MariaDB описания таблиц лежат в frm-файлах.
Подготовка исходного сервера и аудит схемы перед переносом
Хорошая миграция начинается с инвентаризации. На старом сервере собирают три списка: версию и настройку, движки хранения, правила сравнения колонок.
SELECT VERSION(), @@version_comment, @@default_storage_engine;
SELECT table_schema, engine, COUNT(*) AS tables_cnt,
ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) AS size_mb
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','sys','information_schema','performance_schema')
GROUP BY table_schema, engine
ORDER BY size_mb DESC;
SELECT collation_name, COUNT(*) AS columns_cnt
FROM information_schema.columns
WHERE table_schema NOT IN ('mysql','sys','information_schema','performance_schema')
GROUP BY collation_name
ORDER BY columns_cnt DESC;
Отдельно выгружают список учётных записей с плагинами, чтобы оценить объём ручной работы:
SELECT user, host, plugin FROM mysql.user ORDER BY user;
Со списками работают так. Если среди движков мелькает MyISAM, его переводят в InnoDB до окна переключения: в согласованный снимок флага --single-transaction он не попадает. Если правила сравнения целиком из семейства 0900, готовят замену и проверяют сортировку тестами. По коду приложения запускают поиск упоминаний служебной схемы и слова caching_sha2, чтобы не встретиться с ними в час ночи. Затем поднимают стенд и делают холостой прогон: тестовый импорт вскрывает все пять ловушек за вечер и даёт честную оценку времени. Заодно сверяют клиентские библиотеки, старый драйвер PHP может не знать новых умолчаний принимающей стороны.
Пошаговый перенос рабочей базы с MySQL на MariaDB за один вечер
Схема рассчитана на проект из нескольких баз общим объёмом до десятков гигабайт; для обычного сайта или магазина путь ниже отработан годами.
Шаг первый: принимающая сторона. MariaDB ставят рядом, отдельной машиной или вторым экземпляром на том же сервере, и сразу задают набор символов и буферный пул под реальный объём данных:
[mysqld]
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci
innodb_buffer_pool_size = 2G
max_connections = 200
Шаг второй: черновой дамп и тестовый импорт. Выгружают всё пользовательское, не трогая служебные схемы:
mysqldump --single-transaction --routines --triggers --events --hex-blob \
--databases shop crm blog > /root/dump_draft.sql
Флаг --single-transaction снимает согласованный снимок InnoDB без блокировок, --hex-blob спасает бинарные данные, без --routines и --triggers переедут только таблицы. Дальше правка правила сравнения и сам импорт:
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_general_ci/g' /root/dump_draft.sql
mariadb --default-character-set=utf8mb4 < /root/dump_draft.sql
Шаг третий: учётные записи. Хэши паролей между ветками не переносятся, учётки создают заново по списку из аудита. Права смотрят на старом сервере и повторяют:
mysql -e "SHOW GRANTS FOR 'shop'@'localhost';"
CREATE USER 'shop'@'localhost' IDENTIFIED BY 'новый-пароль';
GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE ON shop.* TO 'shop'@'localhost';
FLUSH PRIVILEGES;
Шаг четвёртый: окно переключения. Ночью или в режиме обслуживания на старом сервере закрывают запись:
SET GLOBAL super_read_only = 1;
Затем выполняют финальный дамп теми же флагами, переносят, снимают ограничение уже на MariaDB и переключают конфигурацию приложения. Для базы в несколько гигабайт цикл укладывается в десятки минут на NVMe-диске, точное время подскажет стенд.
Шаг пятый: наблюдение. Первые сутки смотрят журнал ошибок и график времени ответа. Оптимизаторы у веток разные, и у редкого запроса план может измениться: включённый заранее журнал медленных запросов сразу покажет, какого именно.
Обратный переезд с MariaDB на MySQL и его подводные камни
Обратный путь сложнее, потому что расширения MariaDB не имеют аналогов в MySQL. Перед дампом код и схему чистят от четырёх вещей. Последовательности CREATE SEQUENCE переписывают на AUTO_INCREMENT, пересобирая логику выдачи номеров. Таблицы с WITH SYSTEM VERSIONING возвращают к обычным, историю выгружают заранее, иначе она потеряется. Синтаксис RETURNING вырезают из запросов приложения, заменив его вторым запросом. Движок Aria переводят в InnoDB до выгрузки либо строкой после неё:
sed -i 's/ENGINE=Aria/ENGINE=InnoDB/g' /root/dump_back.sql
Зато JSON переезжает честно: MariaDB хранит его как LONGTEXT с ограничением CHECK JSON_VALID, а MySQL версии 8.0.16 и новее такое ограничение понимает и проверяет сам. Правила сравнения general_ci в MySQL присутствуют для совместимости, но сортируют иначе, чем семейство 0900, поэтому тесты с сортировкой прогоняют заранее. Учётки снова создают вручную, теперь уже с плагином caching_sha2_password по умолчанию, и отдельно проверяют, выдержат ли старые коннекторы приложения новый диалог аутентификации.
И про перенос ещё раз: только логический, через дамп, затея "перебросить сервер по scp" закончится переустановкой.
Проверка целостности данных после переезда и план отката
Переезд считается завершённым, когда числа сошлись. Быструю сверку делают по количеству строк: скрипт запускают на обеих сторонах, результаты сравнивают через diff.
for db in shop crm; do
mysql -N -e "SHOW TABLES IN $db" | while read t; do
echo "$db.$t $(mysql -N -e "SELECT COUNT(*) FROM $db.\`$t\`")"
done
done > /root/counts_old.txt
for db in shop crm; do
mariadb -N -e "SHOW TABLES IN $db" | while read t; do
echo "$db.$t $(mariadb -N -e "SELECT COUNT(*) FROM $db.\`$t\`")"
done
done > /root/counts_new.txt
diff /root/counts_old.txt /root/counts_new.txt && echo "БАЗЫ СОВПАЛИ"
Для подозрительных таблиц сверяют контрольные суммы, они ловят искажения при равных счётчиках:
CHECKSUM TABLE shop.orders EXTENDED;
Приложение проверяют по короткому сценарию из реальных действий: вход пользователя, создание заказа, отчёт за вчера. Дальше первый день наблюдают журнал ошибок и время ответа типовых страниц.
Откат готовят до переключения, а не после. Старый сервер неделю держат под рукой в режиме read_only, конфигурацию подключения из приложения не удаляют. Если проблема всплыла в первые часы и новых записей мало, возврат занимает минуты. Если записи уже пошли, путь один: свежий дамп с новой стороны, импорт на старую. Через неделю, когда графики ровные, старый экземпляр выключают, архив конфигураций оставляют на память.
Постепенно переезды превращают выбор ветки из вопроса вкуса в инженерную задачу с цифрами: инвентаризация, прогон, окно, сверка. Обе СУБД спокойно принимают возвращённые базы и продолжают работу, а у администратора остаётся запас знаний на случай обратного маршрута.