# Миграции схемы БД

> Версионируемые скрипты, которые последовательно изменяют структуру базы данных вместе с кодом приложения; инструменты Alembic, Flyway, Liquibase, Django migrations и практики изменений без простоя.

Источник: https://llmdocs.ru/wiki/schema-migrations/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Назначение**: воспроизводимое изменение схемы БД по версиям
- **Хранятся**: в репозитории рядом с кодом
- **Подходы**: версионный (императивный), декларативный (сравнение состояний)
- **Python**: Alembic, Django migrations
- **JVM и универсальные**: Flyway, Liquibase
- **Go и другие**: golang-migrate, goose, Atlas, Prisma Migrate, sqlx migrate
**Миграции схемы базы данных** — упорядоченный набор версионируемых скриптов, каждый из которых переводит структуру базы из одного состояния в следующее: создаёт таблицы, добавляет столбцы и [индексы](https://llmdocs.ru/wiki/database-index.md), переименовывает поля, переносит данные. Миграции хранятся в [системе контроля версий](https://llmdocs.ru/wiki/git.md) вместе с кодом приложения, а специальный инструмент знает, какие из них уже применены к конкретной базе, и применяет недостающие. Так схема на ноутбуке разработчика, в тестах и в продакшене остаётся одинаковой и воспроизводимой.[6]

## Зачем нужны

Без миграций изменения схемы делаются вручную через консоль: кто-то забывает добавить столбец на стенде, порядок изменений теряется, новую базу невозможно поднять с нуля. Миграции решают это:

- история изменений схемы видна в репозитории и проходит ревью, как код;
- новая среда поднимается одной командой;
- изменения схемы выкатываются автоматически в пайплайне [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) вместе с приложением;
- можно откатить изменение (если миграция обратима).

## Как работают

Инструмент создаёт в базе служебную таблицу (`alembic_version`, `django_migrations`, `flyway_schema_history`) с перечнем применённых миграций. Команда «обновить» сравнивает её со списком файлов и выполняет недостающие по порядку, обычно каждую в своей [транзакции](https://llmdocs.ru/wiki/transaction-acid.md).

Два подхода:

- **Версионный** (императивный) — разработчик пишет (или генерирует) последовательность шагов: `V1__create_users.sql`, `V2__add_email.sql`. Так работают Flyway, Alembic, Django, golang-migrate.[3]
- **Декларативный** — описывается желаемое состояние схемы, а инструмент сам вычисляет разницу с текущей базой и строит план изменений: Atlas, Prisma (`db push`), sqldef.[5] Удобно, но план нужно внимательно проверять — особенно удаления.

## Примеры

**Alembic** (для SQLAlchemy) умеет автоматически генерировать миграцию по изменениям моделей [ORM](https://llmdocs.ru/wiki/orm.md):[1]

```bash
alembic revision --autogenerate -m "add user email"
alembic upgrade head       # применить все
alembic downgrade -1       # откатить последнюю
```

```python
def upgrade() -> None:
    op.add_column("users", sa.Column("email", sa.String(255), nullable=True))
    op.create_index("ix_users_email", "users", ["email"], unique=True)

def downgrade() -> None:
    op.drop_index("ix_users_email", table_name="users")
    op.drop_column("users", "email")
```

**Django** делает то же встроенными командами `makemigrations` и `migrate` (см. [Django](https://llmdocs.ru/wiki/django.md)).[2] **Flyway** и **Liquibase** работают с чистыми SQL-файлами или описаниями в XML/YAML и популярны в мире JVM, но подходят для любого стека.[4]

Автогенерацию всегда нужно читать глазами: инструмент может принять переименование столбца за удаление и создание нового — с потерей данных.

## Изменения без простоя

В продакшене база работает под нагрузкой, а приложение выкатывается постепенно: какое-то время старая и новая версии кода работают одновременно. Отсюда два правила.

**1. Блокировки.** Многие операции `ALTER TABLE` берут эксклюзивную блокировку и на большой таблице «подвешивают» все запросы.[7] В [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md):

- индексы создавать с `CREATE INDEX CONCURRENTLY` (вне транзакции);
- новые столбцы добавлять без `DEFAULT`, вычисляемого для каждой строки, или с константным значением по умолчанию (с PG 11 это мгновенно);
- `NOT NULL` и внешние ключи добавлять как `NOT VALID`, а затем проверять отдельно `VALIDATE CONSTRAINT`;
- задавать `SET lock_timeout = '5s'`, чтобы миграция не встала в очередь за долгой транзакцией и не заблокировала всё за собой.

В [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md) для больших таблиц используют онлайн-DDL или инструменты gh-ost и pt-online-schema-change.

**2. Совместимость версий: «расширить и сжать»** (*expand and contract*). Опасные изменения разбивают на несколько выкладок. Например, переименование столбца `name` → `full_name`:

1. **Расширить:** добавить столбец `full_name`; код пишет в оба столбца.
2. **Перенести данные:** заполнить `full_name` для старых строк пачками, чтобы не держать долгую транзакцию.
3. **Переключить:** код читает только `full_name`.
4. **Сжать:** после того как старые версии кода выведены из работы, удалить `name`.

Каждый шаг совместим с соседними версиями приложения, и любой можно откатить.

## Практики

- Одна миграция — одно логическое изменение; уже применённые в общих средах миграции **не редактируются**, ошибки исправляются новой миграцией.
- Миграции данных отделяют от миграций схемы и делают идемпотентными.
- В CI проверяют, что миграции применяются на чистой базе и что модели совпадают со схемой (`alembic check`, `makemigrations --check`); линтеры вроде squawk предупреждают об опасных операциях.
- Перед рискованной миграцией — свежий бэкап и проверенное восстановление (см. [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md)).
- Миграции запускают отдельным шагом развёртывания (job в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), шаг пайплайна), а не при старте каждого экземпляра приложения, чтобы избежать гонок.

## См. также

- [ORM](https://llmdocs.ru/wiki/orm.md)
- [SQL](https://llmdocs.ru/wiki/sql.md)
- [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md)
- [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md)

## Источники

1. [Alembic documentation](https://alembic.sqlalchemy.org/)
2. [Django — Migrations](https://docs.djangoproject.com/en/stable/topics/migrations/)
3. [Flyway documentation](https://documentation.red-gate.com/flyway)
4. [Liquibase documentation](https://docs.liquibase.com/)
5. [Atlas — Declarative schema migrations](https://atlasgo.io/)
6. [Martin Fowler — Evolutionary Database Design](https://martinfowler.com/articles/evodb.html)
7. [PostgreSQL — ALTER TABLE (locking notes)](https://www.postgresql.org/docs/current/sql-altertable.html)
