что такое миграции базы данных и зачем они нужны
В чем суть миграций БД?
Здравствуйте.
В данный момент изучаю Flask, проходя данный туториал:
https://blog.miguelgrinberg.com/post/the-flask-meg.
Так как никакого опыта работы с БД я не имею (совсем чайник), то возникло несколько вопросов после прочтения:
https://blog.miguelgrinberg.com/post/the-flask-meg.
Автор данного туториала использует ORM SQLAlchemy.
После прочтения осталось неясным:
1. Что такое миграция, для чего конкретно нужна и как это связанно с сохранением данных?
2. Чем миграция отличается от db_upgrade or db_downgrade?
3. Что будет, если миграции не производить?
1. Что такое миграция, для чего конкретно нужна и как это связанно с сохранением данных?
переход от одной структуры БД к другой без потери косистентности
2. Чем миграция отличается от db_upgrade or db_downgrade?
3. Что будет, если миграции не производить?
Леша: изменилась модель хранения
Добавили пару полей, БД потеряла 3нф
Для восстановления 3нф нужно создать еще одну модель
Теперь нужно переместить часть данных в новую модель
Если не делать миграцию, то связм потеряются = нет консистентности
А без миграции, есть только вариант с удалением таблицы и созданием двух новых
Леша: миграции производятся при изменении полей моделей
Те, поменялся тип поля у модели = миграция
добавилось поле = миграция
Обьем изменений неважен
Причем не всегда изменения возможно провести в один заход. Иногда приходится делать две и более миграции для изменения одного поля
поменялся тип поля у модели = миграция
добавилось поле = миграция
а если поступить так:
остановить сервер
в базе данных (Mysql) ручками произвести изменения
далее в моделях flask подправить соотвествено
далее стратануть веб сервер.
ТАК НЕЛЬЗЯ? ПОЧЕМУ?
На PHP сайтах делаемже и ничо вроде живы!
sim3x,
Тоесть разработчики PHP (да и других языков) сайтов в течении лет так 30 как минимум говнокодили.
Чот как то не укладывается в голове это определение необходиости миграции.
89109983838, да, все время говнокодили
Только не 30, а 22
Миграции требуются в проектах, которые развиваются и поддерживаются
NOSQL хайп уже давно прошел, им все переболели и забыли
Сравнение и выбор систем миграции данных
Сравнение и выбор систем миграции данных
Модель данных в процессе разработки имеет свойство изменяться, и в какой-то момент она перестает соответствовать базе данных. Конечно же, БД можно удалить, и тогда ORM создаст новую версию, которая будет соответствовать модели, но такая процедура приведет к потере существующих данных. Таким образом, функция системы миграции сводится к тому, чтобы в результате изменения схемы синхронизировать ее с моделью данных в приложении без потери существующих данных.
В рамках данной статьи нам хотелось бы рассмотреть различные инструменты для управления миграциями баз данных. Надеемся, этот обзор будет полезен для разработчиков, столкнувшихся с подобным выбором.
Задача
Доменную модель приложения создают несколько разработчиков одновременно – каждый отвечает за свою логическую часть системы.
В предыдущем поколении DSS в качестве системы управления миграциями использовался классический Entity Framework Migrations (EF 6). Однако, к нему накопились некоторые претензии, главная из которых заключалась в том, что в EF отсутствует вменяемый подход к разрешению конфликтов версий. Этот факт до сих пор нас огорчает при багфиксинге в рамках поддержки, поэтому было принято решение рассмотреть альтернативные варианты.
В результате обсуждения сформировались следующие требования к системе управления миграциями:
А теперь чуть подробнее
EntityFramework Core Migrations
Естественно, это был первый и основной вариант для выбора. Нативный инструмент, работающий из коробки без каких-либо плясок с бубном. Большое количество документации, официальной и не очень, простота и т.д. Однако претензии, предъявлявшиеся к классическому EF, вполне актуальны и для EF Core.
Таким образом для EF Core выделены плюсы:
dbup.github.io
github.com/chucknorris/roundhouse
Этот инструмент управления миграциями, распространяемый под лицензией Apache 2.0, как и предыдущий, работает на движке T-SQL миграций. Судя по всему, разработчики ставили во главу угла решение технических проблем в части поддержки СУБД, а не создание комфортного процесса разработки.
github.com/fluentmigrator/fluentmigrator
Каков же был наш выбор?
Самые горячие споры развернулись вокруг двух параметров – автогенерация миграций и вменяемого решения конфликтов. Прочие факторы пугали гораздо меньше. В итоге, по результатам обсуждения командой было принято решение использовать в новом проекте Fluent Migrator. Ибо решение конфликтов в дальнейшей перспективе принесет гораздо большее количество плюсов.
Опыт 1440 миграций баз данных
Представьте себе Oracle DBA. Ему уже за тридцать, он слегка полноват, носит жилетку, на шее у него висит секретный токен доступа ко всем базам, а в резюме полстраницы пройденных им сертификаций. Суббота. День большого релиза. Кульминация. Время накатывать изменения на базу данных. Он набирает sqlplus, нажимает ENTER и по черному экрану куда-то вверх, в пустоту, устремляются километры SQL команд. Совсем как в звездных войнах. Спустя пять минут все готово. Через час релиз завершен. Работа сделана, день удался. Теперь можно и по паре пива.
Совсем другое дело — понедельник. Выясняется, что некоторые команды не выполнились из-за ошибок, что, впрочем, не остановило скрипт в его безудержном стремлении в черную пустоту. И без того непростая задача разобраться, что сломалось, осложняется еще и некоторым давлением со стороны руководства. В общем, понедельник не задался.
Конечно, это выдуманная история. Ни с кем никогда такого не происходило. По крайней мере, не произошло, если бы работы по изменению схемы базы данных были организованы через миграции.
Что такое инструмент миграции баз данных?
Идея управления изменениями схемы базы данных через миграции крайне проста:
Такой подход дает множество преимуществ по сравнению с организацией изменений в общем SQL файле. Одно только отсутствие merge конфликтов чего стоит.
Тем удивительнее, что сам подход получил популярность сравнительно недавно. Кажется, что общую известность подходу принес фреймворк Ruby on Rails, в котором инструмент миграции был встроен изначально, это был конец 2005 года. Немногим ранее о подходе писал Martin Fowler, 2003. Вероятно, все дело в том, что разработка начала активно адаптировать использование системы контроля версий только в начале этого века. Еще в 2000 году первый пункт теста Joel Spolsky звучал “Do you use source control?” — это наводит на мысль о том, что системами контроля версий тогда пользовались далеко не все. Но мы отвлеклись.
Восемь лет с MyBatis Migrations
Мы в Wrike начали использовать подход изменения баз данных через миграции в 2010 году, 29 марта, в половину первого. С тех пор мы реализовали 1440 миграций, содержащий 6436 прямых изменений и 5015 обратных. В целом, у нас накопился некоторый опыт использования инструмента MyBatis Migrations в связке с PostgreSQL.
Если коротко, мы ни разу не пожалели. Случись такое, что вы еще не используете Migrations или нечто подобное, самое время начать. Да, Pentium 4 тоже устарел.
Но о достоинствах чего-либо говорить скучно, давайте сразу к трудностям.
Специфика работы с PostgreSQL
Создание UNIQUE индекса и смена PRIMARY KEY также требуют определенной сноровки, но эти операции делаются сравнительно редко, чтобы на них останавливаться.
Специфика работы с кластером
Инструмент управления миграциями базы данных хорош до тех пор, пока у вас одна база данных. Все веселее, если баз у вас несколько. Особенно если у вас несколько типов баз данных, каждой из которых по нескольку экземпляров.
В итоге, после git pull разработчик должен накатить изменения на первый экземпляр первой базы данных, потом на второй экземпляр, потом на первый экземпляр второй базы данных и так далее – такой принцип. Тут впору писать утилиту управления утилитой управления миграциями базы данных. Тотальная автоматизация.
Жонглирование ролями
Не секрет, что роли как сущности живут не на уровне отдельной базы данных, но на уровне всего сервера баз данных, по крайней мере, в Postgres. При этом в миграции может потребоваться указать REVOKE INSERT ON some_table FROM some_role ; Ожидать, что роли будут заранее сконфигурированы в production еще можно, но для dev или staging это уже затруднительно. При этом в разработке, конечно, все базы существуют на одном локальном сервере, так что просто написать в миграции CREATE ROLE нельзя, а IF NOT EXISTS не поддерживается. Все решается просто:
Смотрите! Я их ловлю и подбрасываю, ловлю и подбрасываю, это же так просто.
Немного реальности разработки
Тестовые окружения
С долгоживущими окружениями все еще сложнее. QA, знаете ли, не любят, приходя на работу, видеть безукоризненно чистую базу данных. Я не знаю, почему так, но факт есть факт. Так что состояние баз, используемых в ручном тестировании, приходится поддерживать в целостности. А это не всегда просто.
Тонкость в том, что если миграция применена к базе данных, в нее записывается идентификатор миграции. А если код миграции позже был изменен, базы это уже не коснется. Если изменения некритичные, код может успешно доехать до production. Рассинхрон. Безусловно, это безобразие. Первый принцип работы с миграциями — никогда не менять написанные миграции, а всегда создавать новые. Но иногда так хочется схалтурить — я вот тут чуть-чуть поменяю, ничего же не сломается, ведь правда. Конечно! Валяйте!
Если бы миграции подписывались после ревью, можно было бы запретить применять черновики к staging. А еще можно было бы сохранять в changelog не только идентификатор миграции, но и checksum — тоже полезно.
Верните как было
Особенно коварный поворот случается, когда задачу отменяют: делали-делали и передумали. Вполне нормальная ситуация. Раз код больше не нужен, ветку следует удалить. А там же была миграция… а она же уже в staging… а, … опа. Хороший повод проверить, умеете ли вы восстановить бекап репозитория. Хотя вспомнить, что там было, пожалуй, проще.
Сделайте UNDO еще раз
MySql-миграции: что это и как реализовать простым php-скриптом
Когда разрабатываешь веб-приложение не один, а в команде и/или на нескольких машинах, рано или поздно сталкиваешься с проблемой синхронизации кода проекта и базы данных. Для управления кодом есть системы контроля версий, в частности, git, а для СУБД придуманы миграции.
Есть много готовых разнообразных инструментов, которые занимаются миграциями, но!
Поэтому всех, кому интересно узнать, как самим сделать простую утилиту миграций, написав полсотни строк php-кода, прошу в статью.
Идея миграций
Идея довольно проста: в проекте создаем отдельную папку sql, куда складываем sql-файлы с миграциями, то есть, со скриптами, которые меняют содержимое базы, а также один php-файл, который эти миграции и накатывает.
Нужно учесть 2 вещи: во-первых, каждая миграция должна выполняться строго один раз, а во-вторых, в строго определенном порядке. Это разумно и обязательно, потому как если нам прилетают от коллеги 2 миграции, одна из которых создает таблицу users, а другая добавляет в нее тестовых пользователей, то мы хотим выполнить эти скрипты именно в таком порядке и не добавить при этом данные в базу больше одного раза.
Проблему повторных выполнений миграций мы решим, записывая в отдельную таблицу уже отработавшие скрипты, а порядок выполнения установим четкими правилами именования sql-файлов. Как это решается в коде, увидим чуть позже, а пока займемся подготовкой самих тестовых миграций (исходники всех миграций и php-скрипта в конце статьи)
Создаем тестовые sql-скрипты
Пусть у нас есть тестовая база данных под названием test. Мы работаем с ней какое-то время и решили внедрить миграции. Есть разумное правило: самая первая миграция должна содержать в себе полный дамп уже существующих сущностей в базе. Уточню: миграции помогают не только последовательно расширять уже существующую базу, но еще и накатить эту самую базу с нуля, например, для новых людей в команде.
Перед началом выполнения миграций я предполагаю, что указанная база данных уже существует, поэтому в миграции нигде не указывается название базы. На мой взгляд, это хорошо в том плане, что на одной машине программист может работать с разными базами и с разными их версиями. Поэтому у нас скрипта создания базы не будет.
Напишем первую миграцию: дамп базы и таблица versions. Пусть на момент внедрения миграций у нас есть таблица goods с парой товаров. Их нужно скинуть в скрипт и в тот же скрипт добавить таблицу versions. В итоге файл будет выглядеть так.
0000_base.sql
На заметку: возможно, Вам не удобно писать sql-скрипты руками, Вы привыкли создавать и заполнять таблицы через phpMyAdmin или другой инструмент. Спешу успокоить, все известные мне утилиты позволяют генерировать такой sql-код автоматически. То есть Вы можете работать с базой, как удобно, а при подготовке файла-миграции вытащить нужный скрипт из условного phpMyAdmin-a в режиме copy-paste.
Порядковые номера в начале каждого файла нужны, чтобы правильно отсортировать файлы. Только в этом случае миграции будут выполняться в правильном порядке. После _ идет краткое описание миграции, которое нужно исключительно для нашего удобства, чтобы понимать, что делает тот или иной скрипт, не заглядывая в него.
Пишем php-код для запуска миграций
Каркас migration.php, базовые константы и функции
Нам нужно написать фунцию подключения к базе данных и общую логику работы скрипта. Создадим файл migration.php, кинем его в папку sql рядом с миграциями и напишем в нем следующее:
Дальше функция glob вытащит все файлы из указанной папки по нужной маске *.sql.
Версионная миграция структуры БД: от теории к практике
В топике рассматривается еще одна простая система версионирования структуры БД, а также ИМХО, почему нам не подходят другие.
Случайно наткнулся на топик хабраюзера Shedal Версионная миграция структуры базы данных: основные подходы. Хотел написать развернутый комментарий, но посмотрел на дату создания последнего и решил оформить отдельным топиком.
Целью данного топика не является обзор подходов к версионированию БД — он замечательно сделан в статье по ссылке выше — тут лишь будет краткое ИМХО по подходам, которые нас по какой-то причине не устроили.
Этот топик в первую очередь будет интересен разработчикам, только присматривающимся к миграциям БД и изучающим инструменты. Если вы уже давно используете какие-то системы/техники и довольны ими, то ничего нового тут, возможно, и не узнаете.
Постановка задачи
Разрабатываем мы на PHP+MySQL, используем фреймворк Kohana. Нужно было организовать как-то процесс миграции структуры БД, чтобы как-то автоматизировать деплоймент на тестовый сервер и на продакшен. Мы не пишем простые сайты-визитки, но и супер-сложные проекты тоже. Основные проекты в большинстве своем не очень большие (15-30 таблиц в БД; 50-200 человекочасов). Все написанное ниже справедливо для нас, но вполне возможно, что не подойдет под более сложные проекты или под другие технологии/фреймворки (во многих фреймворках есть своя реализация миграций БД, поэтому смысла использовать другие велосипеды, конечно же, нету)
Метод уподобления структуры БД исходному коду
Попробовали несколько тулз и отказались от этот варианта.
Метод инкрементных изменений
Вариантов тут несколько: либо мы храним написанные вручную ALTER-скрипты, либо пишем их на PHP (или любом другом, на котором мы пишем наше приложение). Пример такой сферической миграции в вакууме:
В общем-то довольно неплохой вариант. Насколько я знаю, такое реализовано в Doctrine и других фреймворках. Несколько слов против: все-таки это не всегда оправданное лишнее усложнение нашей системы. Почему мы не использовали — из коробки Kohana не поддерживает эти миграции, использовать для этого Doctrine тоже не хочется — слишком уж он монструозен ИМХО. Это справедливо для наших проектов. У вас все может быть по-другому.
Для нас показался самым удобным метод, когда пишутся вручную ALTER-скрипты на SQL. Тулз и техник для этого масса, ссылки на них в топике по ссылке в самом верху. Все они хороши, но мы решили упростить систему до невозможности, чтобы весь функционал накатывания изменений поместился в несколько строк и не нужно было для этого использовать готовые тулзы.
Наше решение
В первую очередь отказываемся от возможности отката. Я лично считаю, что эта опция в большинстве случаев вообще не нужна, а вопросов с ней возникает масса. Далее отказываемся от правил именования скриптов миграции, от их номеров и отдельного номера версии для БД.
Отсутствие правила сквозной нумерации дельта-скриптов чудесным образом решает главную проблему такого подхода — параллельная разработка в разных ветках репозитория. Поясню.
Предположим, у нас в транке три дельты — как описано выше. Вася делает бранч, скажем, для добавления чекбокса «запомнить меня», Петя в это время продолжает править мелкие баги в транке. Вася добавляет дельту 0004-user-tokens.sql, Петя добавляет дельты 0004-users-change-username-length.sql и 0005-users-add-email.sql. Окей. После мержа в транке будет две дельты под «номером» 0004 — но нам неважен номер, мы применяем все непримененные, поэтому изменения Васи применятся к базе в транке у Пети без проблем.
Конечно, могут возникать конфликты при одновременном изменении одних и тех же колонок таблицы, но эта ситуация крайне редка.