миграции базы данных
Миграции базы данных — механизм управления изменениями схемы реляционной базы данных посредством версионированных скриптов. Каждая миграция описывает конкретное изменение схемы (добавление таблицы, изменение типа столбца, создание индекса) и применяется в строго определённом порядке. Миграции базы данных решают задачу синхронизации схемы БД между разными окружениями (разработка, стейджинг, продакшн) и участниками команды.
Зачем нужны миграции: проблема без них
Без миграций изменения схемы применяются вручную: разработчик выполняет ALTER TABLE в консоли и говорит коллегам «обновите свою базу». Это приводит к классическим проблемам: схема на ноутбуке разработчика отличается от продакшна, изменения не воспроизводимы, накопленные изменения не задокументированы. Откат к предыдущей версии превращается в ручную работу по восстановлению. Миграции решают все эти проблемы системно.
Структура системы миграций
Типичная система миграций состоит из трёх элементов:
- Файлы миграций — SQL-скрипты или файлы на языке программирования с именами, содержащими версию или временную метку: 20240115_add_user_email_index.sql или V2__Add_user_email_index.sql.
- Таблица истории — специальная таблица в БД (schema_migrations, flyway_schema_history), где хранится информация о применённых миграциях: версия, временная метка, контрольная сумма.
- Инструмент миграций — 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 необязателен: укажите, если хотите ответ только для вас (мы не шлём рассылки).