← Назад в словарь

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 — согласованность в распределённых системах

Смотри также (статьи на сайте)

Смотри также (сниппеты)

Смотри также (термины)

Мини-FAQ

Можно ли без миграций?

Ответ: Можно, но это быстро приводит к ручному аду и рассинхронизации между dev/staging/production. Миграции — это документация изменений БД.

Всегда ли возможен rollback?

Ответ: Нет. Некоторые изменения необратимы:

  • ✅ Добавить поле → можно удалить
  • ❌ Удалить поле с данными → данные потеряны
  • ⚠️ Изменить тип данных → может потребоваться конвертация с потерей

Как применять миграции в production?

Ответ:

  1. Бэкап БД
  2. Применение на staging
  3. Проверка работоспособности
  4. Применение на production (в maintenance window или zero-downtime)
  5. Мониторинг после применения

Сколько миграций хранить?

Ответ: Все. Миграции — это история изменений БД. Но можно делать «squash» старых миграций в одну базовую (например, раз в год).