В статье автор пытается рассказать об основных подходах к миграции схем баз данных.
Ключевые слова: миграция схем баз данных, идемпотентность, конвергентность.
В настоящее время все информационные и информационно-аналитические системы не обходятся без использования баз данных. Изменения в структуре данных [1], которые отражают изменения в реальной морфологии объектов или пользовательских требований, привели к исследованию эволюции схемы и ее версионировании. Управление версиями схемы включает концепцию эволюции схемы, которая в свою очередь включает концепцию модификации или миграции схемы.
Миграция схем данных является неотъемлемой задачей при переходе от одной структуры схем данных к другой. Сложность миграции данных заключается в наличии большой разницы между текущей структурой схемы данных и новой, а также достаточно большую сложность составляет наличие существующих зависимостей между объектами. В данной магистерской диссертации исследованы принципы, которые помогают определить алгоритм действий для миграции схемы данных и ее сущностей.
У большинства подходов есть общий принцип: им необходимо основание — некоторое эталонное состояние базы данных (БД), от которого можно отталкиваться. Что из себя представляет основание — это слепок структуры базы данных [2] для версии, которая принята за базовую. Имея основание, впоследствии всегда можно будет создать БД заново. Чтобы получить БД со структурой самой последней версии, нужно применить к этой базе данных все миграции, созданные в процессе разработки.
При разработке программного продукта и, соответственно, написании кода разработчики пользуются системами контроля версий, такими как Git или Subversion. Данные системы позволяют вести совместный процесс разработки несколькими сотрудниками, хранить только разницу между версиями кода, отслеживать и, при необходимости, возвращаться к конкретной версии исходного кода. В то же время применение систем контроля версий при работе со структурами схем данных ограничено.
Также, одной из причин миграции схем данных является наличие каких-либо аномалий либо увеличение нагрузки при анализе работы программного продукта с базой данных, т. к. быстрота работы БД напрямую зависит от ее структуры и выполненной оптимизации.
В результате в процессе развития программного продукта отследить изменения структуры данных весьма проблематично ввиду того, что DDL, язык определения схем данных, не предусматривает документирование изменения структуры на каждом шаге.
Наиболее оптимальным решением задачи миграции схем данных и является следование данным принципам: идемпотентности и конвергентности. Отличительной особенностью такого подхода является то, что скрипт, который удовлетворяет условиям принципов, описывает состояние, к которому объект должен быть приведен, а не действия, которые требуется произвести над ним.
Идемпотентность обеспечивает отсутствие изменений объекта при выполнении скрипта повторно в случае, если скрипт был выполнен успешно при первом его запуске. То есть основная идея этого подхода — написание миграционных файлов таким образом, чтобы их можно было выполнить больше одного раза. При первой попытке выполнить любую из SQL-команд, изменения будут применены; при всех последующих попытках ничего не произойдет.
Соблюдение данного принципа позволяет избежать дублирования и искажения данных. Однако, в случае невыполнения скрипта или неудачного завершения его выполнения, система, при повторном выполнении данного скрипта, будет пытаться прийти к тому состоянию, которое было задано в качестве желаемого. Такое поведение системы обусловлено принципом конвергентности, который направлен на приведение системы в нужное состояние при каждом следующем запуске одного и того же скрипта без выполнения операций, успешно выполненных ранее. Т. е. изменения, не выполненные при одной попытке, система будет пытаться выполнить еще раз при повторном запуске.
Основные подходы:
Метод инкрементных изменений:
Суть данного метода заключается в хранении всей истории изменения структуры базы данных в виде файлов-скриптов в заранее строго определенном порядке и именовании. Выполнение данных скриптов должно быть в соответствующем порядке.
Самый первый файл, который появится в папке миграции, — основание. После этого любое изменение в БД отражается в виде нового файла-миграции с именем вида [номер файла]. [версия].sql.
Помимо хранения файлов, описанных в первом методе, существует дополнительный шаг по добавлению в базу данных специальной таблицы, в которой будет храниться история всех изменений в базе данных.
После выполнения каждого файла-миграции в эту таблицу будет заноситься запись со всеми данными о миграции.
Текущую версию БД можно будет получить из записи с максимальной датой.
Завершающий штрих в этом подходе — программа/скрипт, который будет обновлять БД с текущей версии до последней.
Выполнять миграцию БД автоматически довольно просто, т. к. номер последней выполненной миграции можно получить из служебной таблицы, например, MigrationHistory, которая добавляется разработчиком самостоятельно для хранения списка выполненных файлов-миграций (скриптов). После этого остается только применить все файлы с бо́льшими номерами. Сортировать файлы можно по номеру.
При таком подходе модуль должен выполнять задачу добавления записей о выполненных миграциях в таблицу служебную таблицу MigrationHistory.
Плюсы:
- Быстрое и удобное выполнение миграции до последней версии;
- Механизм нумерации версий. Номер текущей версии хранится прямо в БД;
- Для максимального удобства нужны средства автоматизации выполнения миграций.
Минусы:
- При попытке использования модуля миграции на основе существующей базы данных, однако при отсутствии служебной таблицы MigrationHistory, обновить базу данных до последней версии не представляется возможным, т. к. истории о выполненных файлах-миграциях, а также самих миграций нет.
В качестве дополнительных удобств, такой скрипт может уметь создавать текущую версию БД заново, сначала применяя на БД основание, а затем выполняя стандартную операцию по миграции до последней версии.
Метод идемпотентных изменений:
Примечание: в данном методе используется стандарт SQL-92, который включает в себя базу данных information_schema, которая обеспечивает доступ к метаданным базы данных.
Метаданные представляют собой данные относительно данных, имени базы данных или таблицы, тип данных столбца или привилегии доступа. Внутри information_schema имеется несколько таблиц только для чтения. Они фактически являются представлением (view), а не обычными таблицами, так как не имеется никаких файлов, связанных с ними.
В базе данных information_schema существует таблица с именем tables, которая хранит в себе информацию об описании существующих таблиц.
Каждый пользователь MySQL имеет право обратиться к этим таблицам, но может видеть только строки в таблицах, которые соответствуют объектам, для которых пользователь имеет соответствующие привилегии доступа. В некоторых случаях, пользователи, которые имеют недостаточные привилегии, будут видеть NULL.
Под идемпотентностью понимается свойство объекта оставаться неизменным при повторной попытке его изменить.
Основная идея этого подхода — написание миграционных файлов таким образом, чтобы их можно было выполнить на базе данных больше одного раза. При первой попытке выполнить любую из SQL-команд, изменения будут применены; при всех последующих попытках ничего не произойдет.
Благодаря ключевой фразе IF NOT EXISTS, MySQL попытается создать таблицу только в том случае, если таблицы с таким именем еще не существует. Однако такой синтаксис доступен не во всех СУБД; к тому же, даже в MySQL его можно использовать не для всех команд.
Полную информацию о структуре базы данных можно получить из специальных системных таблиц, находящихся в базе данных с именем information_schema. Эта база данных и ее таблицы — часть стандарта SQL-92, поэтому этот способ можно использовать на любой из современных СУБД. В предыдущем примере используется таблица information_schema.tables (системная таблица), в которой хранятся данные о всех таблицах. Подобным образом можно проверять существование и метаданные полей таблиц, хранимых процедур, триггеров, схем, и, фактически, любых других объектов структуры базы данных.
Плюсы:
- Очень удобное выполнение миграций с любой промежуточной версии до последней — нужно всего лишь выполнить на базе данных один файл.
Минусы:
- Потенциально возможны ситуации, в которых будут теряться данные, за этим придется следить. Примером может служить удаление таблицы, и затем создание другой таблицы с тем же именем. Если при удалении проверять только имя, то обе операции (удаление и создание) будут происходить каждый раз при выполнении скрипта, несмотря на то, что когда-то уже выполнялись;
- Для того, чтобы изменения были идемпотентными, нужно потратить больше времени (и кода) на их написание.
Благодаря тому, что обновить базу данных до последней версии очень просто, и делать это можно вручную, этот метод показывает себя в выгодном свете в том случае, если есть много серверов, которые доступны для конечных пользователей и их нужно часто обновлять.
Выводы:
Сравнив данные подходы, можно сделать вывод, что больше всего плюсов имеет подход на основе инкрементных изменений. Используя репозиторий, можно решить несколько минусов данного подхода. Например, при переименовании скрипта с существующим именем разработчик будет об этом уведомлен. С помощью ветвлений можно решить задачу по обновлению разных рабочих БД, используя различные наборы скриптов для каждого ветвления. Пропадает строгая структура хранения каталога со скриптами. Разработчик делает удобную структуру для себя. Хранение скриптов возможно в удаленном репозитории.
Литература:
- Версионирование структуры БД с помощью Liquibase [Электронный ресурс] — Режим доступа: http://easy-code.ru/lesson/database-versioning-liquibase
- Дейт К. Дж. Введение в системы баз данных. — 8-е изд. — М.: «Вильямс», 2006. — 1328 с.