Когда нужна смена СУБД: реальные сценарии
Мы не раз встречали проекты, где компания решает перейти с 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 с нормализацией). Стоимость рассчитывается индивидуально после оценки объёма данных и сложности трансформации. Свяжитесь с нами для консультации и получите индивидуальный план миграции без обязательств. Закажите предварительный аудит вашей базы!
Редизайн и миграция сайта: смена CMS, сохранение SEO
Клиент пришёл через 6 недель после самостоятельного редизайна: «Мы переехали с WordPress на Tilda, трафик упал на 70%». Открываю Google Search Console — 847 страниц отдают 404, URL-структура полностью изменилась, не было ни одного 301-редиректа. Яндекс ещё не переиндексировал новый сайт, позиции рухнули. Восстановление заняло 4 месяца и обошлось в потерю выручки около 2 млн рублей за квартал. Наш опыт — более 7 лет и 80+ успешных миграций, гарантируем сохранение позиций при правильном подходе.
Почему миграции ломают SEO
Поисковики проиндексировали конкретные URL. Если /catalog/shoes/nike-air-max-270 превратился в /products/nike-air-max-270 без 301-редиректа — весь ссылочный вес страницы, весь трафик, все позиции уходят в никуда. Google говорит, что 301 передаёт ~99% PageRank, но на практике позиции восстанавливаются за 2–8 недель, а не мгновенно.
Чаще всего SEO ломают не из злого умысла, а потому что разработчик не думает о URL-структуре как о публичном API. Вот типичные поломки:
| Проблема |
Причина |
Решение |
| Дублированный контент |
Новый сайт открывается параллельно со старым |
Отключить индексацию dev-версии, настроить canonical |
| Потеря метаданных |
Title и description остались в старой CMS |
Экспорт через API, массовый импорт с проверкой |
| Изменение canonical |
Пагинация и фильтры сбросились |
Зафиксировать до разработки, внедрить в шаблон |
| Скорость просела |
Тяжёлые секции, неоптимизированные изображения |
Оптимизировать LCP, CLS, TTFB до запуска |
Как восстановить трафик после неудачной миграции?
Если трафик упал — действуйте немедленно:
- Краул нового сайта на 404 и сравнение с предмиграционным списком URL.
- Создание редиректов для всех потерянных страниц с трафиком >0.
- Проверка структурированных данных и мета-тегов на тестовой выборке.
- Ежедневный мониторинг Coverage в Search Console и позиций по топ-50 запросам.
- Если спустя 2 недели трафик не восстанавливается — глубокий аудит редиректов (транзитивность, цепочки, циклы).
В нашей практике такой случай: крупный интернет-магазин потерял 50% трафика при переезде с Битрикса на React + Strapi. За три дня восстановили 95% редиректов, через 3 недели трафик вернулся на 90% от исходного.
Предмиграционный аудит: что нельзя пропустить
До начала разработки нового сайта нужно:
- Полный краул текущего сайта через Screaming Frog или Sitebulb. Получить список всех индексируемых URL с трафиком из Google Search Console.
- Выгрузить все страницы с органическим трафиком >0 за последние 6 месяцев — это приоритет для редиректов.
- Зафиксировать все внешние ссылки (backlinks) на конкретные страницы — Ahrefs, Semrush.
- Сфотографировать текущие позиции по ключевым запросам — база для сравнения после миграции.
- Сохранить Core Web Vitals из Search Console за предыдущие 90 дней.
Таблица для фиксации:
| Этап аудита |
Инструмент |
Критичность |
| Сбор URL |
Screaming Frog + GSC |
Высокая |
| Трафик по страницам |
Google Analytics / Search Console |
Высокая |
| Внешние ссылки |
Ahrefs / Majestic |
Средняя |
| Позиции |
Яндекс.Wordstat / Serpstat |
Средняя |
| Core Web Vitals |
GSC CrUX |
Высокая |
Свяжитесь с нами для детального предмиграционного аудита — мы поможем выявить все риски и составить план действий.
Маппинг URL и редиректы
Для проекта с 200+ страницами создаём таблицу маппинга: старый URL → новый URL → статус (301, объединён с другой страницей, удалён). Каждая строка проходит проверку: реально ли контент переехал именно сюда.
В Laravel редиректы через конфигурационный файл и middleware, не через .htaccess — это быстрее и управляемо. Для WordPress → Next.js: редиректы настраиваются в next.config.js (статические) и на уровне Nginx/CDN для динамических. Старый .htaccess на shared хостинге с 500+ строками редиректов — особый ад. Каждый редирект проверяется последовательно, производительность падает. Переносим в Nginx map директиву или Redis-кэш для динамического поиска. Подробнее в Wikipedia: HTTP 301.
Миграция контента из разных CMS
WordPress → Headless CMS (Contentful, Strapi, Sanity):
WordPress REST API или WP All Export для экспорта постов, метаполей, медиафайлов. Скрипт миграции на Node.js: парсим экспорт, трансформируем структуру, загружаем через API CMS. Медиафайлы перегружаем в новое хранилище, обновляем ссылки в контенте. Типичная проблема — shortcodes в контенте WordPress ([gallery id="123"]): нужен парсер и трансформация в новый формат.
1С-Битрикс → современный стек:
Битрикс хранит контент в нестандартных таблицах с IBLOCK_ELEMENT_PROPERTY. Прямой SQL-экспорт через phpMyAdmin или Bitrix API. Трансформация — самая долгая часть из-за специфики структуры данных Битрикса.
Тяжёлые WYSIWYG → структурированный контент:
Годы редактирования в FCKEditor/TinyMCE оставляют inline-стили, нестандартные теги, сломанные атрибуты. HTML sanitize + трансформация в Markdown или Portable Text (Sanity) с ручной проверкой проблемных страниц.
| CMS |
Инструменты миграции |
Сложность |
Риски |
| WordPress |
WP All Export, WP-CLI, REST API |
Средняя |
Shortcodes, meta fields |
| 1C-Битрикс |
Bitrix API, SQL-экспорт |
Высокая |
Сложная структура, свойства инфоблоков |
| Joomla |
J2XML, прямая выгрузка из БД |
Высокая |
Устаревшие расширения |
| Tilda/Readymag |
Экспорт через API (ограничен) |
Средняя |
Нет полного доступа к контенту |
SEO-сохранение технических элементов
Структурированные данные (Schema.org) — если на старом сайте были Product, Article, BreadcrumbList разметки, они должны быть и на новом. Google Search Console → Enhancement reports покажут потерю rich snippets.
Sitemap XML: генерируется автоматически, отправляется в GSC через день после запуска. Старый sitemap остаётся до полной переиндексации.
hreflang для мультиязычных сайтов: если теги потерялись при миграции, через несколько недель начнутся конфликты между языковыми версиями в выдаче.
Open Graph и Twitter Card мета-теги — часто забывают при смене шаблона, страницы перестают корректно отображаться при шаринге в соцсетях.
Запуск и мониторинг первых недель
DNS propagation: переключение DNS занимает до 48 часов, планируйте запуск с запасом. Cloudflare как DNS-провайдер — propagation занимает минуты, не часы.
После запуска ежедневно мониторим: Search Console → Coverage (ошибки индексации), Analytics → органический трафик, сравнение с аналогичным периодом прошлого года, краулинг сайта на 404-ошибки.
Первые 2 недели — критический период. Если трафик падает на 30%+ — немедленный аудит редиректов и сравнение с предмиграционным краулом.
Чек-лист на запуск (спойлер)
- [ ] Все 301 редиректы работают и не образуют цепочек
- [ ] Sitemap отправлен в GSC и Яндекс.Вебмастер
- [ ] Прописаны canonical на всех страницах
- [ ] Проверено отображение Open Graph / Twitter Card
- [ ] Скорректированы robots.txt и мета-теги noindex
- [ ] Core Web Vitals в зелёной зоне (LCP <2.5s, CLS <0.1, INP <200ms)
Что входит в работу
Результаты, которые вы получаете:
- План миграции с маппингом URL и редиректов в формате Excel/Google Sheets.
- Настроенные 301 редиректы на серверном уровне (Nginx/Cloudflare/Vercel).
- Перенесённый контент с проверкой целостности: изображения, мета-поля, ссылки.
- Структурированные данные (Schema.org) на новом сайте, идентичные старым или улучшенные.
- Отчёт по SEO: динамика позиций через 1, 3 и 6 недель после запуска.
- Мониторинг Coverage в Search Console с уведомлениями об ошибках.
- Гарантия сохранения позиций: если трафик падает более чем на 15% в течение первого месяца — бесплатный аудит и коррекция.
Сроки и ориентиры
- Редизайн с миграцией небольшого сайта (до 100 страниц): 4–8 недель.
- Миграция e-commerce с 500+ страниц товаров: 8–16 недель.
- Только техническая часть миграции (редиректы, метаданные) без редизайна: 1–3 недели.
Стоимость рассчитывается индивидуально по объёму. Средняя экономия клиента за счёт сохранения трафика после миграции — от 300 000 до 500 000 рублей в год.
Получите консультацию по вашему проекту — мы ответим в течение дня. Закажите предмиграционный аудит вашего сайта и получите точную смету с планом редиректов. Свяжитесь с нами, чтобы обсудить детали.