Schema migration
Schema migration — миграция структуры
TL;DR
Schema migration — процесс изменения структуры базы данных (таблицы, индексы, поля) с сохранением данных и совместимости. Автоматизирует применение изменений БД между релизами приложения.
Краткое определение
Schema migration — версионирование и применение изменений структуры базы данных через скрипты миграции, которые могут применяться и откатываться автоматически.
Оригинал и перевод
- Язык: английский
- Оригинал: Schema migration / Database migration
- Буквальный перевод: миграция схемы / миграция БД
- Русские аналоги: миграция структуры БД, миграция схемы данных
Синонимы и варианты написания
- DB migration
- Database schema migration
- Миграция структуры БД
- Database versioning
Где используется
- Backend-приложения: Laravel Migrations, Django Migrations, Rails Migrations
- CI/CD пайплайны: автоматическое применение миграций при деплое
- High-load системы: zero-downtime деплой изменений БД
- Monolith и microservices: каждый сервис управляет своей БД
Когда это важно
Schema migration критична в следующих сценариях:
- Частые релизы: несколько изменений БД в неделю
- Zero-downtime деплой: нельзя останавливать приложение
- Командная разработка: синхронизация структуры между разработчиками
- Production данные: нельзя потерять данные при изменении схемы
Типы миграций
1. Добавление поля/таблицы
-- ✅ Безопасно: можно применять без простоя ALTER TABLE users ADD COLUMN phone VARCHAR(20); CREATE TABLE orders (id INT PRIMARY KEY, user_id INT, created_at TIMESTAMP); CREATE INDEX idx_orders_user_id ON orders(user_id);
2. Изменение типа данных
-- ⚠️ Требует осторожности: может быть долго на больших таблицах ALTER TABLE users ALTER COLUMN email TYPE VARCHAR(255); -- ✅ Безопасный способ (постепенный): -- 1. Добавить новое поле ALTER TABLE users ADD COLUMN email_new VARCHAR(255); -- 2. Скопировать данные UPDATE users SET email_new = email; -- 3. Переключить приложение на новое поле -- 4. Удалить старое поле ALTER TABLE users DROP COLUMN email;
3. Удаление поля/таблицы
-- ⚠️ Нельзя сразу: приложение ещё использует поле -- ✅ Безопасный способ: -- 1. Перестать писать в поле (приложение) -- 2. Выждать время (часы/дни) -- 3. Удалить поле ALTER TABLE users DROP COLUMN old_field;
Инструменты миграции
Laravel Migrations (PHP)
// Создание миграции
php artisan make:migration add_phone_to_users_table
// Файл миграции
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPhoneToUsersTable extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('phone')->nullable()->after('email');
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('phone');
});
}
}
// Применение миграций
php artisan migrate // Применить все
php artisan migrate:status // Статус
php artisan migrate:rollback // Откатить последнюю
Django Migrations (Python)
# migration 0003_add_phone_field.py
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0002_previous_migration'),
]
operations = [
migrations.AddField(
model_name='user',
name='phone',
field=models.CharField(max_length=20, null=True, blank=True),
),
]
# Команды
python manage.py makemigrations # Создать миграции
python manage.py migrate # Применить
python manage.py showmigrations # Показать статус
Flyway (Java, SQL-based)
-- V1__create_users_table.sql
CREATE TABLE users (
id BIGINT PRIMARY KEY,
email VARCHAR(255) NOT NULL
);
-- V2__add_phone_column.sql
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
-- Команды
flyway migrate # Применить миграции
flyway info # Статус
flyway undo # Откатить (требует платной версии)
Liquibase (XML/YAML/SQL)
# changelog.yaml
databaseChangeLog:
- changeSet:
id: 1
author: andrey
changes:
- addColumn:
tableName: users
columns:
- column:
name: phone
type: VARCHAR(20)
Best practices для миграций
✅ Делайте
- Обратимость: всегда пишите
down()метод - Тестирование: проверяйте миграции на staging перед production
- Бэкап: делайте бэкап перед применением на production
- Идемпотентность: миграция должна применяться безопасно несколько раз
- Версионирование: каждая миграция имеет уникальный номер
- Документирование: комментируйте сложные изменения
❌ Не делайте
- Изменение данных в миграции: только схема, данные — отдельными скриптами
- Длинные транзакции: разбивайте на части
- Блокирующие операции:
ALTER TABLEна больших таблицах блокирует запись - Зависимости от данных: не предполагайте конкретные значения в БД
Zero-downtime миграции
Паттерн: Expand and Contract
Этап 1 (Expand): Добавить новое поле Этап 2: Приложение пишет в оба поля Этап 3: Перенос данных со старого на новое Этап 4: Приложение читает из нового поля Этап 5 (Contract): Удалить старое поле
Пример: переименование поля
-- Миграция 1: Добавить новое поле ALTER TABLE users ADD COLUMN display_name VARCHAR(255); -- Приложение (код): -- INSERT INTO users (name, display_name) VALUES ($name, $name); -- Миграция 2: Перенос данных UPDATE users SET display_name = name WHERE display_name IS NULL; -- Миграция 3: Удалить старое поле (через 1-2 недели) ALTER TABLE users DROP COLUMN name;
Паттерн: Parallel Change
Изменение с одновременной поддержкой старого и нового:
-- Было: status ENUM('new', 'paid', 'shipped')
-- Стало: status VARCHAR(50)
-- 1. Добавить новое поле
ALTER TABLE orders ADD COLUMN status_new VARCHAR(50);
-- 2. Конвертировать данные
UPDATE orders SET status_new = status;
-- 3. Приложение использует оба поля
-- 4. Удалить старое после миграции
ALTER TABLE orders DROP COLUMN status;
Типичные ошибки
- ❌ Нет отката: миграция применена, но нужно вернуться
- ❌ Изменение данных: миграция упала на половине данных
- ❌ Блокировка таблицы:
ALTER TABLEна 100M+ записях - ❌ Зависимость между миграциями: миграция 5 требует миграцию 3
- ❌ Ручные изменения в БД: миграции не соответствуют реальности
Аналоги и связанные термины
- Database versioning — версионирование БД
- Rollback — откат миграции
- Zero-downtime deployment — деплой без простоя
- Liquibase / Flyway — инструменты миграции
- Eventual consistency — согласованность в распределённых системах
Смотри также (статьи на сайте)
- PostgreSQL для веб-разработчиков — миграция с MySQL, JSON, оптимизация
- Blue/Green deployment — развёртывание без простоя
Смотри также (сниппеты)
- PostgreSQL: pg_dump и pg_restore — бэкап перед миграцией
- Идемпотентный агент с блокировкой — защита от параллельного запуска миграций
Смотри также (термины)
- Blue/Green deployment — деплой без простоя
- ACID — атомарность транзакций
- Replication — репликация данных
Мини-FAQ
Можно ли без миграций?
Ответ: Можно, но это быстро приводит к ручному аду и рассинхронизации между dev/staging/production. Миграции — это документация изменений БД.
Всегда ли возможен rollback?
Ответ: Нет. Некоторые изменения необратимы:
- ✅ Добавить поле → можно удалить
- ❌ Удалить поле с данными → данные потеряны
- ⚠️ Изменить тип данных → может потребоваться конвертация с потерей
Как применять миграции в production?
Ответ:
- Бэкап БД
- Применение на staging
- Проверка работоспособности
- Применение на production (в maintenance window или zero-downtime)
- Мониторинг после применения
Сколько миграций хранить?
Ответ: Все. Миграции — это история изменений БД. Но можно делать «squash» старых миграций в одну базовую (например, раз в год).