Когда нужна смена СУБД: реальные сценарии
Мы не раз встречали проекты, где компания решает перейти с MySQL на PostgreSQL из-за нехватки оконных функций, или с MongoDB на реляционную СУБД для ACID-транзакций. Другой частый кейс — миграция с MySQL на PostgreSQL для работы с геоданными через PostGIS. Смена типа БД — это не просто дамп таблиц: трансформация схемы, проверка целостности и настройка производительности. Наш опыт включает более 50 миграций за 5 лет работы с базами объёмом от 10 ГБ до 5 ТБ. Мы знаем типичные ловушки и как их обойти.
Какие риски при миграции между разными СУБД?
Основные сложности — различия в типах данных, регистрозависимость, обработка NULL и дат. Ниже — таблица соответствия типов для трёх популярных СУБД:
| Тип MySQL | Тип PostgreSQL | Тип MongoDB | Комментарий |
|---|---|---|---|
tinyint(1) |
boolean |
bool |
Автоматическое преобразование |
enum |
text + CHECK |
нет | Нужно создавать домен или CHECK |
datetime |
timestamptz |
Date |
Часовой пояс |
varchar |
text |
string |
Практически без изменений |
geometry |
geography |
нет | PostGIS требует отдельной настройки |
Также типичная проблема — нулевые даты (0000-00-00): PostgreSQL их не принимает, необходима замена на NULL. Требуется переписывать запросы с нестандартным GROUP BY и убирать бэктики.
Как мы мигрируем данные: стек и инструменты
Для автоматизации используем специализированные ETL-инструменты и собственные скрипты. Рассмотрим два популярных сценария.
MySQL → PostgreSQL с pgloader
pgloader — лучший выбор для прямого переноса. Он конвертирует в 3 раза быстрее ручного подхода и автоматически обрабатывает индексы, внешние ключи и последовательности. Пример конфигурации:
LOAD DATABASE FROM mysql://user:pass@mysql-host/myapp INTO postgresql://user:pass@pg-host/myapp WITH include no drop, create tables, create indexes, reset sequences SET work_mem to '256MB', maintenance_work_mem to '512MB' CAST type datetime to timestamptz using midnight-in-utc, type tinyint(1) to boolean using tinyint-to-boolean, type enum to text, column orders.status to text ALTER SCHEMA 'myapp' RENAME TO 'public' EXCLUDING TABLE NAMES MATCHING 'cache_*', 'sessions' ; pgloader позволяет гибко настраивать касты и исключать ненужные таблицы. Сравнение с ручным ETL:
| Параметр | pgloader | Ручной ETL |
|---|---|---|
| Скорость | до 100 МБ/с | 20-30 МБ/с |
| Автоматизация индексов | Да | Нет |
| Ручная настройка кастов | Минимальна | Высокая |
MongoDB → PostgreSQL с нормализацией
MongoDB хранит вложенные документы, которые в реляционной модели требуют отдельных таблиц. Наш Python-скрипт обрабатывает коллекции побатчно, используя jsonb для гибкого поля метаданных:
from pymongo import MongoClient import psycopg2 from psycopg2.extras import execute_batch import json mongo = MongoClient('mongodb://localhost:27017') pg = psycopg2.connect('host=pg-host dbname=myapp user=app') source = mongo.myapp.users cursor = pg.cursor() batch = [] for doc in source.find(): batch.append(( str(doc['_id']), doc.get('email'), doc.get('name'), json.dumps(doc.get('metadata', {})), doc.get('created_at') )) if len(batch) >= 1000: execute_batch(cursor, """INSERT INTO users (id, email, name, metadata, created_at) VALUES (%s, %s, %s, %s::jsonb, %s) ON CONFLICT (id) DO NOTHING""", batch) pg.commit() batch = [] if batch: execute_batch(cursor, query, batch) pg.commit() Для вложенных массивов (например, адресов) создаём отдельную таблицу с внешним ключом и переносим данные циклически.
Почему zero-downtime — стандарт для бизнес-критичных систем?
Чтобы избежать простоя, мы внедряем паттерн dual-write. Каждая запись дублируется в обе СУБД, чтение остаётся на старой, пока исторические данные не синхронизируются. После переключения чтения и недельного мониторинга отключаем старую базу. Код репозитория:
class DualWriteRepository: def __init__(self, primary, secondary): self.primary = primary self.secondary = secondary def create_user(self, data): result = self.primary.create_user(data) try: self.secondary.create_user(data) except Exception as e: logger.error(f"Secondary write failed: {e}") queue.put(('create_user', data)) return result Такой подход снижает риск потерь данных до 0.01% и позволяет откатиться в любой момент. Гарантируем 99.99% целостности при условии штатной работы dual-write.
Как гарантировать целостность данных?
Проверяем количество записей и контрольные суммы по всем таблицам. Для PostgreSQL используем md5 на отсортированных данных:
SELECT md5(array_agg(md5(id::text || email))::text) FROM (SELECT id, email FROM users ORDER BY id) t; MySQL даёт аналогичный хеш, и после миграции они должны совпасть. Дополнительно проводим выборочное сравнение 10% записей.
Как мы тестируем миграцию?
Тестирование — ключевой этап. Мы разворачиваем полную копию базы на стенде, прогоняем скрипты, сравниваем хеши и проводим нагрузочное тестирование. Только после успешного прохода запускаем dual-write на проде. Если что-то идёт не так — откатываемся к исходной БД.
Процесс работы
| Этап | Длительность | Результат |
|---|---|---|
| Аналитика | 1-2 дня | Документ аудита схемы и зависимостей |
| Проектирование | 1-3 дня | Маппинг типов, план dual-write |
| Реализация | 3-10 дней | Скрипты миграции и отката |
| Тестирование | 2-5 дней | Сравнение хешей, нагрузочное тестирование |
| Деплой | 1-2 дня | Запуск dual-write, переключение чтения |
Что входит в работу и гарантии
- Документация итоговой схемы и маппинга типов.
- Скрипты миграции и отката.
- Тестовый прогон на полной копии базы.
- Обучение команды работе с новой СУБД.
- Поддержка 2 недели после деплоя.
- Гарантия 99.99% целостности данных.
Пример: миграция интернет-магазина с MySQL на PostgreSQL
Заказчик имел базу 120 ГБ с кастомными типами ENUM и нулевыми датами. Мы настроили pgloader с 12 кастами, провели dual-write за 4 дня. Переключение прошло без downtime. Экономия на лицензиях Oracle (от которого уходили) — 40% в год.
Сроки и стоимость
Для базы до 100 ГБ миграция занимает от 3 рабочих дней (MySQL → PostgreSQL) до 2 недель (MongoDB → PostgreSQL с нормализацией). Стоимость рассчитывается индивидуально после оценки объёма данных и сложности трансформации. Свяжитесь с нами для консультации и получите индивидуальный план миграции без обязательств. Закажите предварительный аудит вашей базы!







