Pull to refresh

Версионная миграция структуры БД: от теории к практике

Website development *
В топике рассматривается еще одна простая система версионирования структуры БД, а также ИМХО, почему нам не подходят другие.


Случайно наткнулся на топик хабраюзера Shedal Версионная миграция структуры базы данных: основные подходы. Хотел написать развернутый комментарий, но посмотрел на дату создания последнего и решил оформить отдельным топиком.

Целью данного топика не является обзор подходов к версионированию БД — он замечательно сделан в статье по ссылке выше — тут лишь будет краткое ИМХО по подходам, которые нас по какой-то причине не устроили.

Этот топик в первую очередь будет интересен разработчикам, только присматривающимся к миграциям БД и изучающим инструменты. Если вы уже давно используете какие-то системы/техники и довольны ими, то ничего нового тут, возможно, и не узнаете.

Постановка задачи


Разрабатываем мы на PHP+MySQL, используем фреймворк Kohana. Нужно было организовать как-то процесс миграции структуры БД, чтобы как-то автоматизировать деплоймент на тестовый сервер и на продакшен. Мы не пишем простые сайты-визитки, но и супер-сложные проекты тоже. Основные проекты в большинстве своем не очень большие (15-30 таблиц в БД; 50-200 человекочасов). Все написанное ниже справедливо для нас, но вполне возможно, что не подойдет под более сложные проекты или под другие технологии/фреймворки (во многих фреймворках есть своя реализация миграций БД, поэтому смысла использовать другие велосипеды, конечно же, нету)

Метод уподобления структуры БД исходному коду


Когда в системе контроля версий хранится вся схема БД, а для миграции БД до последней версии генерируется diff-скрипт, преобразующий исходную БД к последней. В теории все прекрасно, на практике возникают проблемы:
  • существующие инструменты не всегда могут (даже теоретически) решить эту задачу автоматически. Самый простой пример — переименование столбца или таблицы.
  • лично я никогда не доверю программе генерировать ALTER скрипты для продакшена, а это значит, что перед применением их надо просматривать/править руками


Попробовали несколько тулз и отказались от этот варианта.

Метод инкрементных изменений


Вариантов тут несколько: либо мы храним написанные вручную ALTER-скрипты, либо пишем их на PHP (или любом другом, на котором мы пишем наше приложение). Пример такой сферической миграции в вакууме:
class Migration_0001 extends Migration_Abstract
{
  public function up()
  {
     $this->createTable("users")
       ->column("id", self::PK)
       ->column("username", self::VARCHAR);
  }

  public function down()
  {
     $this->dropTable("users");
  }
}

В общем-то довольно неплохой вариант. Насколько я знаю, такое реализовано в Doctrine и других фреймворках. Несколько слов против: все-таки это не всегда оправданное лишнее усложнение нашей системы. Почему мы не использовали — из коробки Kohana не поддерживает эти миграции, использовать для этого Doctrine тоже не хочется — слишком уж он монструозен ИМХО. Это справедливо для наших проектов. У вас все может быть по-другому.

Для нас показался самым удобным метод, когда пишутся вручную ALTER-скрипты на SQL. Тулз и техник для этого масса, ссылки на них в топике по ссылке в самом верху. Все они хороши, но мы решили упростить систему до невозможности, чтобы весь функционал накатывания изменений поместился в несколько строк и не нужно было для этого использовать готовые тулзы.

Наше решение


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

Все изменения БД хранятся в отдельных файлах .sql (мы, как и многие, называем их дельтами) в одной папке. Изменения накатываются в алфавитном порядке. Примененные дельты сохраняются в табличке changelog (которая загружается из отдельного «начального» sql-дампа). При миграции применяются все не примененные дельты. Всё. Пример папки с дельтами:
deltas
|- 0001-users.sql
|- 0002-users-add-username.sql
'- 0003-users-drop-last-login.sql

Код, обрабатывающий эту систему миграций очень прост и может быть написан и встроен куда угодно. Мы, например, используем phing. Кому-то хватит простого php-файла.

Отсутствие правила сквозной нумерации дельта-скриптов чудесным образом решает главную проблему такого подхода — параллельная разработка в разных ветках репозитория. Поясню.

Предположим, у нас в транке три дельты — как описано выше. Вася делает бранч, скажем, для добавления чекбокса «запомнить меня», Петя в это время продолжает править мелкие баги в транке. Вася добавляет дельту 0004-user-tokens.sql, Петя добавляет дельты 0004-users-change-username-length.sql и 0005-users-add-email.sql. Окей. После мержа в транке будет две дельты под «номером» 0004 — но нам неважен номер, мы применяем все непримененные, поэтому изменения Васи применятся к базе в транке у Пети без проблем.

Конечно, могут возникать конфликты при одновременном изменении одних и тех же колонок таблицы, но эта ситуация крайне редка.
Tags: версионная миграцияверсионированиебазы данных
Hubs: Website development
Total votes 31: ↑25 and ↓6 +19
Comments 68
Comments Comments 68

Popular right now