Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое миграция в БД
Миграция базы данных (database migration) — это контролируемое изменение структуры (схемы) БД из одной версии в другую. Миграции — это версионирование DDL операций, как Git для вашей БД.
Зачем нужны миграции
- Версионирование схемы БД — отслеживание истории изменений
- Простота развёртывания — один скрипт вместо ручных SQL команд
- Откат (rollback) — возможность вернуться на шаг назад
- Teamwork — команда работает с одной версией БД
- CI/CD интеграция — автоматическое применение при деплое
- Data safety — целостность данных при изменении схемы
Типы миграций
Forward Migration (up) — применение:
-- migrations/001_create_users_table.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT NOW()
);
Backward Migration (down) — откат:
-- Откатывает созданную таблицу
DROP TABLE users;
Примеры распространённых миграций
Добавление нового столбца:
-- v002_add_phone_to_users.sql
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
Создание индекса:
-- v003_add_email_index.sql
CREATE INDEX idx_users_email ON users(email);
Добавление внешнего ключа:
-- v004_create_posts_table.sql
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(255),
content TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
Изменение типа данных:
-- v005_change_email_type.sql
ALTER TABLE users
ALTER COLUMN email TYPE VARCHAR(500);
Инструменты для миграций
Python backend (популярное):
- Alembic (SQLAlchemy ORM):
alembic init migrations
alembic revision -m "add user table"
alembic upgrade head # Применить все миграции
alembic downgrade -1 # Откатить на одну версию назад
- Django Migrations (для Django):
python manage.py makemigrations
python manage.py migrate
python manage.py migrate app_name 0001 # Откатить
PostgreSQL (raw SQL):
- Goose (Go, но используется в Python проектах):
goose -dir migrations postgres "..." up
goose -dir migrations postgres "..." down
- Liquibase (Java-based, language-agnostic):
<changeSet id="1" author="dev">
<createTable tableName="users">
<column name="id" type="INT" autoIncrement="true">
<constraints primaryKey="true"/>
</column>
<column name="email" type="VARCHAR(255)"/>
</createTable>
</changeSet>
Структура файлов миграций
Стандартная структура проекта:
project/
├── migrations/
│ ├── versions/
│ │ ├── 001_create_users_table.sql
│ │ ├── 002_add_posts_table.sql
│ │ ├── 003_add_email_index.sql
│ │ └── 004_rename_column.sql
│ ├── env.py # Настройки Alembic
│ ├── script.py.mako # Template для новых миграций
│ └── versions/
├── models.py # SQLAlchemy модели
└── run.sh # Скрипт применения миграций
Именование файлов:
- Обязательно с версией:
001_,002_, ... - Описательное имя:
001_create_users_table.sql - Не используй: спецсимволы, пробелы, русские буквы
Workflow разработчика
# 1. Создание новой миграции
alembic revision -m "add phone column to users"
# 2. Правим созданный файл
# migrations/versions/abc123_add_phone_column_to_users.py
# 3. Применяем локально для тестирования
alembic upgrade head
# 4. Тестируем приложение
python test.py
# 5. Откатываем для чистоты
alembic downgrade -1
alembic upgrade head # Применяем снова
# 6. Коммитим
git add migrations/
git commit -m "add phone column"
# 7. При деплое обновляет БД автоматически
# CI/CD pipeline запускает: alembic upgrade head
Лучшие практики
- Один файл — одна логическая операция:
-- ✓ Хорошо: одна таблица
CREATE TABLE users (...);
-- ✗ Плохо: в одном файле несколько операций
CREATE TABLE users (...);
CREATE TABLE posts (...);
CREATE INDEX idx_users_email ON users(email);
- Откат должен быть безопасным:
-- ✓ Безопасный откат
ALTER TABLE users DROP COLUMN phone;
-- ✗ Опасный откат (теряем данные)
DROP TABLE users; -- Можно потерять данные!
- Миграции должны быть идемпотентными:
-- ✓ Хорошо: не падает при повторном запуске
CREATE TABLE IF NOT EXISTS users (...);
DROP TABLE IF EXISTS temp_table;
-- ✗ Плохо: падает при повторном запуске
CREATE TABLE users (...); -- ERROR: таблица уже существует
- Документируй сложные миграции:
-- v010_refactor_user_statuses.sql
-- ОПИСАНИЕ: переносим статусы из VARCHAR в отдельную таблицу
-- ИМПАКТ: миграция может занять 10+ минут на большой таблице
-- ОТКАТ: долгий процесс, убедись перед откатом
BEGIN;
-- ... сложная логика ...
COMMIT;
- Тестируй на staging сначала:
app deploy staging --run-migrations # Тестируем на staging
app deploy production --run-migrations # Только потом на prod
Типичные проблемы
Проблема: миграция не откатывается
-- Если забыл DOWN скрипт
RULLBACK; -- Откат всей транзакции
-- Потом пишем правильный DOWN скрипт
Проблема: миграция на большой таблице зависает
-- Решение: используй CONCURRENTLY для индексов
CREATE INDEX CONCURRENTLY idx_large_table ON big_table(column);
-- Или добавь LOCK TIMEOUT
SET lock_timeout = '5min';
Проблема: два разработчика создали миграции с одинаковым номером
# Git merge conflict на миграциях
# Решение: переименуй одну миграцию, обнови зависимости
001_feature_a.sql → 001_feature_a.sql
001_feature_b.sql → 002_feature_b.sql # Переименовано
Заключение
Миграции БД — это критически важная часть backend разработки. Они обеспечивают:
- Reproducibility — один и тот же process everywhere
- Safety — можно откатить при проблемах
- History — видна эволюция структуры
- Automation — можно интегрировать в CI/CD
Любой professional backend должен уметь работать с миграциями.