В топике рассматривается еще одна простая система версионирования структуры БД, а также ИМХО, почему нам не подходят другие.
Случайно наткнулся на топик хабраюзера Shedal Версионная миграция структуры базы данных: основные подходы. Хотел написать развернутый комментарий, но посмотрел на дату создания последнего и решил оформить отдельным топиком.
Целью данного топика не является обзор подходов к версионированию БД — он замечательно сделан в статье по ссылке выше — тут лишь будет краткое ИМХО по подходам, которые нас по какой-то причине не устроили.
Этот топик в первую очередь будет интересен разработчикам, только присматривающимся к миграциям БД и изучающим инструменты. Если вы уже давно используете какие-то системы/техники и довольны ими, то ничего нового тут, возможно, и не узнаете.
Разрабатываем мы на PHP+MySQL, используем фреймворк Kohana. Нужно было организовать как-то процесс миграции структуры БД, чтобы как-то автоматизировать деплоймент на тестовый сервер и на продакшен. Мы не пишем простые сайты-визитки, но и супер-сложные проекты тоже. Основные проекты в большинстве своем не очень большие (15-30 таблиц в БД; 50-200 человекочасов). Все написанное ниже справедливо для нас, но вполне возможно, что не подойдет под более сложные проекты или под другие технологии/фреймворки (во многих фреймворках есть своя реализация миграций БД, поэтому смысла использовать другие велосипеды, конечно же, нету)
Когда в системе контроля версий хранится вся схема БД, а для миграции БД до последней версии генерируется diff-скрипт, преобразующий исходную БД к последней. В теории все прекрасно, на практике возникают проблемы:
Попробовали несколько тулз и отказались от этот варианта.
Вариантов тут несколько: либо мы храним написанные вручную ALTER-скрипты, либо пишем их на PHP (или любом другом, на котором мы пишем наше приложение). Пример такой сферической миграции в вакууме:
В общем-то довольно неплохой вариант. Насколько я знаю, такое реализовано в Doctrine и других фреймворках. Несколько слов против: все-таки это не всегда оправданное лишнее усложнение нашей системы. Почему мы не использовали — из коробки Kohana не поддерживает эти миграции, использовать для этого Doctrine тоже не хочется — слишком уж он монструозен ИМХО. Это справедливо для наших проектов. У вас все может быть по-другому.
Для нас показался самым удобным метод, когда пишутся вручную ALTER-скрипты на SQL. Тулз и техник для этого масса, ссылки на них в топике по ссылке в самом верху. Все они хороши, но мы решили упростить систему до невозможности, чтобы весь функционал накатывания изменений поместился в несколько строк и не нужно было для этого использовать готовые тулзы.
В первую очередь отказываемся от возможности отката. Я лично считаю, что эта опция в большинстве случаев вообще не нужна, а вопросов с ней возникает масса. Далее отказываемся от правил именования скриптов миграции, от их номеров и отдельного номера версии для БД.
Все изменения БД хранятся в отдельных файлах .sql (мы, как и многие, называем их дельтами) в одной папке. Изменения накатываются в алфавитном порядке. Примененные дельты сохраняются в табличке changelog (которая загружается из отдельного «начального» sql-дампа). При миграции применяются все не примененные дельты. Всё. Пример папки с дельтами:
Код, обрабатывающий эту систему миграций очень прост и может быть написан и встроен куда угодно. Мы, например, используем phing. Кому-то хватит простого php-файла.
Отсутствие правила сквозной нумерации дельта-скриптов чудесным образом решает главную проблему такого подхода — параллельная разработка в разных ветках репозитория. Поясню.
Предположим, у нас в транке три дельты — как описано выше. Вася делает бранч, скажем, для добавления чекбокса «запомнить меня», Петя в это время продолжает править мелкие баги в транке. Вася добавляет дельту 0004-user-tokens.sql, Петя добавляет дельты 0004-users-change-username-length.sql и 0005-users-add-email.sql. Окей. После мержа в транке будет две дельты под «номером» 0004 — но нам неважен номер, мы применяем все непримененные, поэтому изменения Васи применятся к базе в транке у Пети без проблем.
Конечно, могут возникать конфликты при одновременном изменении одних и тех же колонок таблицы, но эта ситуация крайне редка.
Случайно наткнулся на топик хабраюзера 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 — но нам неважен номер, мы применяем все непримененные, поэтому изменения Васи применятся к базе в транке у Пети без проблем.
Конечно, могут возникать конфликты при одновременном изменении одних и тех же колонок таблицы, но эта ситуация крайне редка.