миграции базы данных

Миграции базы данных — механизм управления изменениями схемы реляционной базы данных посредством версионированных скриптов. Каждая миграция описывает конкретное изменение схемы (добавление таблицы, изменение типа столбца, создание индекса) и применяется в строго определённом порядке. Миграции базы данных решают задачу синхронизации схемы БД между разными окружениями (разработка, стейджинг, продакшн) и участниками команды.

Зачем нужны миграции: проблема без них

Без миграций изменения схемы применяются вручную: разработчик выполняет ALTER TABLE в консоли и говорит коллегам «обновите свою базу». Это приводит к классическим проблемам: схема на ноутбуке разработчика отличается от продакшна, изменения не воспроизводимы, накопленные изменения не задокументированы. Откат к предыдущей версии превращается в ручную работу по восстановлению. Миграции решают все эти проблемы системно.

Структура системы миграций

Типичная система миграций состоит из трёх элементов:

  1. Файлы миграций — SQL-скрипты или файлы на языке программирования с именами, содержащими версию или временную метку: 20240115_add_user_email_index.sql или V2__Add_user_email_index.sql.
  2. Таблица истории — специальная таблица в БД (schema_migrations, flyway_schema_history), где хранится информация о применённых миграциях: версия, временная метка, контрольная сумма.
  3. Инструмент миграций — CLI или библиотека, применяющая миграции в правильном порядке, пропуская уже применённые.

Up и Down миграции

Каждая миграция традиционно содержит два метода:

  • up — применяет изменение (создаёт таблицу, добавляет столбец, создаёт индекс).
  • down — откатывает изменение (удаляет таблицу, удаляет столбец). Позволяет откатиться к предыдущей версии.

Не все изменения обратимы: удаление данных нельзя автоматически откатить. Инструменты вроде Flyway не поддерживают down-миграции в базовой версии — откат выполняется «вперёд» через новую миграцию.

Популярные инструменты миграций

  • Flyway — Java-инструмент с поддержкой SQL и Java-миграций. Используется в Spring Boot-проектах. Версионированные файлы (V1__, V2__) применяются по порядку.
  • Liquibase — декларативные миграции в XML, YAML, JSON или SQL. Поддерживает сравнение схем и генерацию миграций из diff.
  • Alembic — стандарт для SQLAlchemy/Python. Поддерживает autogenerate (сравнивает модели с БД и генерирует миграцию).
  • Django Migrations — встроен в Django. Автоматически генерирует миграции при изменении моделей.
  • Prisma Migrate — декларативные миграции из Prisma Schema. Генерирует SQL и применяет его.
  • golang-migrate — CLI для Go-проектов с поддержкой множества СУБД.
  • Sqitch — change management, основанный на зависимостях, а не на версиях.

Безопасные миграции в продакшне

Применение миграций на работающей базе данных требует осторожности. Опасные операции:

  • ADD COLUMN NOT NULL без DEFAULT — блокирует таблицу на время добавления столбца. Решение: добавить столбец с DEFAULT, потом заполнить данные, потом убрать DEFAULT.
  • DROP COLUMN — необратимо и блокирует таблицу. Решение: сначала перестать использовать столбец в коде, потом удалить.
  • Переименование таблицы/столбца — ломает работающий код. Решение: использовать паттерн expand/contract (добавить новый, перенести данные, переключить код, удалить старый).
  • Создание индекса без CONCURRENTLY — блокирует таблицу на время построения. В PostgreSQL: CREATE INDEX CONCURRENTLY.

Миграции в CI/CD

Хорошая практика — автоматически применять миграции в пайплайне деплоя: запустить инструмент миграций до старта нового кода приложения. Это гарантирует, что схема БД всегда соответствует развёртываемой версии кода. Для Zero-Downtime deployment важно, чтобы миграции были обратно совместимы: новая схема должна поддерживать и старый, и новый код одновременно (rolling deployment).

Контроль версий и командная работа

Файлы миграций хранятся в системе контроля версий рядом с кодом. Конфликты при слиянии веток решаются созданием новой миграции, объединяющей обе ветки. Контрольная сумма файлов (используется в Flyway, Liquibase) защищает от случайного изменения уже применённых миграций: если файл изменился после применения, инструмент выдаст ошибку.

Частые вопросы

  • Чем миграции отличаются от seed-данных?

    Миграции изменяют схему базы данных: создают/удаляют таблицы, добавляют столбцы, создают индексы. Seed-данные наполняют таблицы начальными данными (справочники, тестовые записи). Это разные задачи: схема мигрируется во все окружения, seed-данные часто нужны только в разработке и стейджинге.

  • Как откатить миграцию в продакшне?

    Если инструмент поддерживает down-миграции (Alembic, Knex), можно выполнить rollback. Более безопасный подход — создать новую «forward» миграцию, отменяющую нежелательное изменение. Это сохраняет историю изменений. Данные, удалённые предыдущей миграцией, нужно восстанавливать из резервной копии.

  • Что делать, если две ветки создали миграции с одинаковым номером версии?

    Это классическая проблема в команде. Решение зависит от инструмента: в Flyway конфликт версий вызовет ошибку — нужно перенумеровать одну из миграций. Django обнаруживает конфликт и предлагает создать merge-миграцию. Использование временных меток (timestamp) вместо порядковых номеров снижает вероятность конфликтов.

Не хватает деталей?

Напишите, что уточнить по теме «миграции базы данных» — это помогает улучшать материал и подсказывает, какие термины добавить дальше. Email необязателен: укажите, если хотите ответ только для вас (мы не шлём рассылки).

Поделиться