Реализация миграции данных между типами БД (PostgreSQL ↔ MySQL ↔ MongoDB)

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация миграции данных между типами БД (PostgreSQL ↔ MySQL ↔ MongoDB)
Сложная
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Реализация миграции данных между типами БД (PostgreSQL ↔ MySQL ↔ MongoDB)

Переход между разными СУБД — один из наиболее сложных типов миграций. Различия в типах данных, поведении NULL, автоинкрементах, поддержке JSON и транзакционной семантике требуют тщательного маппинга и тестирования.

Распространённые сценарии

  • MySQL → PostgreSQL (выход из vendor lock-in, лучшая поддержка JSON/JSONB, window functions)
  • MongoDB → PostgreSQL (нормализация данных, ACID транзакции)
  • PostgreSQL → MongoDB (шардирование, гибкая схема для определённых сущностей)
  • MySQL → MySQL другой мажорной версии (через dump/restore с трансформацией)

MySQL → PostgreSQL

Инструмент: pgloader

# Установка
apt install pgloader

# Базовая миграция
pgloader mysql://user:pass@mysql-host/myapp \
         postgresql://user:pass@pg-host/myapp

pgloader автоматически:

  • Конвертирует типы данных
  • Мигрирует индексы и первичные ключи
  • Переносит внешние ключи
  • Обрабатывает AUTO_INCREMENTSERIAL/BIGSERIAL

Кастомная конфигурация pgloader:

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'
;

Проблемы при MySQL → PostgreSQL

Проблема MySQL PostgreSQL Решение
Case sensitivity user = User userUser Нормализовать регистр
ENUM Native type Нет нативного Конвертировать в text + CHECK
Datetime Нет timezone timestamptz Явно указать часовой пояс
GROUP BY Гибкий Строгий (ONLY_FULL_GROUP_BY) Переписать запросы
Zero values 0000-00-00 Не поддерживается Конвертировать в NULL
Backtick quotes Допустимы Не допустимы Заменить на "

MongoDB → PostgreSQL

ETL-подход с использованием Python

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')

# Исходная коллекция MongoDB
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', {})),  # JSONB в PG
        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()

Нормализация вложенных документов

MongoDB-документ:

{
  "_id": "user_123",
  "email": "[email protected]",
  "addresses": [
    { "type": "home", "city": "Moscow", "zip": "101000" },
    { "type": "work", "city": "St. Petersburg", "zip": "190000" }
  ]
}

PostgreSQL-схема:

CREATE TABLE users (
  id TEXT PRIMARY KEY,
  email TEXT UNIQUE NOT NULL
);

CREATE TABLE user_addresses (
  id BIGSERIAL PRIMARY KEY,
  user_id TEXT REFERENCES users(id),
  type TEXT,
  city TEXT,
  zip TEXT
);

Трансформация при миграции:

for doc in source.find():
    cursor.execute("INSERT INTO users (id, email) VALUES (%s, %s)",
                   (str(doc['_id']), doc['email']))

    for addr in doc.get('addresses', []):
        cursor.execute(
            "INSERT INTO user_addresses (user_id, type, city, zip) VALUES (%s, %s, %s, %s)",
            (str(doc['_id']), addr.get('type'), addr.get('city'), addr.get('zip'))
        )

PostgreSQL → MySQL

Прямой путь через mysqldump с трансформацией не существует. Используется:

  1. Экспорт в CSV: COPY table TO '/tmp/table.csv' CSV HEADER
  2. Создание схемы вручную с учётом типов MySQL
  3. Импорт: LOAD DATA INFILE '/tmp/table.csv' INTO TABLE table FIELDS TERMINATED BY ',' ENCLOSED BY '"'

Или через ETL-инструмент Airbyte / dbt / Apache Nifi.

Стратегия zero-downtime при смене типа БД

  1. Запустить новую БД параллельно со старой
  2. Написать dual-write слой в приложении: каждая запись идёт в обе БД
  3. Запустить фоновый процесс синхронизации исторических данных
  4. После выравнивания — перевести чтение на новую БД
  5. Через неделю после стабильной работы — отключить 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}")
            # Не прерывать запрос — пишем в очередь для retry
            queue.put(('create_user', data))
        return result

Верификация после миграции

-- Сравнение количества записей
SELECT 'users' as table_name, COUNT(*) FROM users
UNION ALL
SELECT 'orders', COUNT(*) FROM orders
UNION ALL
SELECT 'products', COUNT(*) FROM products;

-- Сравнение контрольных сумм (PostgreSQL)
SELECT md5(array_agg(md5(id::text || email))::text)
FROM (SELECT id, email FROM users ORDER BY id) t;

Срок выполнения

MySQL → PostgreSQL для базы до 50GB — 3–5 рабочих дней. MongoDB → PostgreSQL с нормализацией схемы — 1–2 недели.