Технология проведения миграции данных в крупных проектах. Методика организации проведения миграции данных Что за птица такая - information_schema

Миграция данных


Миграция данных – многоэтапный процесс перемещения баз данных, программного обеспечения, финансовых или других бизнес-данных между различными ИТ-системами. Продуманный план перехода позволит плавно перенести базы данных, программы и приложения, а также любые иные данные в облако провайдера без неожиданных рисков простоя бизнес-процессов. DEAC обеспечивает надежный пошаговый перенос данных из собственного или размещенного у третьих лиц ИТ-оборудования в инфраструктуру дата-центров DEAC .

Пошаговый план миграции
Эксперты DEAC контролируют и документируют весь процесс миграции данных, поддерживая прозрачность и эффективность проекта

Миграция в облако или сервер
Вне зависимости от географического расположения и используемых систем хранения данных, DEAC обеспечит полную интеграцию данных без риска потери данных

Минимальное влияние на активные бизнес-процессы
Подробный план миграции сохраняет полную производительность приложений, защищая от проблем технической несовместимости или внезапного простоя

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

Выберите опытного поставщика услуг и получите качественный
и бесперебойный процесс миграции данных.


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


Миграция облака

Миграция базы данных

Миграция приложений


DEAC предоставляет полный процесс миграции из собственной инфраструктуры клиента в облако или из одной облачной среды в другую (cloud-to-cloud migration ). Перемещение данных, информационных хранилищ, приложений, и других ИТ-элементов бизнеса в облако позволяет сохранить безопасность и доступность без неожиданных простоев процессов. DEAC использует специализированные облачные инструменты для полноценной интеграции данных или систем.


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


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

УЗНАТЬ БОЛЬШЕ О ДРУГИХ УСЛУГАХ:

Сергей Бердачук, 1.0 2006.12.01

Казалось бы, что наличие уже существующей информационной системы (ИС) должно упростить и ускорить разработку новой ИС на основе старой, но на практике все обычно происходит с точностью до наоборот. Во первых, так как возникла необходимость в создании новой ИС, то это чаще всего означает, что ранее созданная ИС была создана с существенными изъянами и изобилует разнообразными ошибками.

Обычно, ото ИС, которая писалась на протяжении многих лет различными разработчиками. При этом проектная документация чаще всего находится в жалком состоянии, а порой и вообще отсутствует. «Настоящие» программисты не пишут документации, а тем более не документируют программный код. Зачем, ведь все просто и прозрачно. Тем не менее, когда смотришь на свой же код спустя пол года, то довольно сложно разобраться, что же там делалось. Особенно, если за это время было сделано несколько других проектов.

Мало того, каждый новый разработчик обычно не утруждает себя тщательным изучением ни кода, ни архитектуры системы. Так как сроки всегда «горят», то просто пишутся «примочки» для временного решения насущной проблемы. В результате получается «каша», состоящая из множества разношерстных модулей и каким то чудесным образом состыкованных технологий, которые порой не совместимы друг с другом. Положение усугубляется использованием устаревших систем управления базами данных (СУБД) для хранения данных, например dbase-III, FoxPro или Clipper. Отсутствие понятия транзакции, а при неумелом проектировании и ссылочной целостности приводит к многочисленным нарушениям целостности данных. Можно считать, что повезло, если в старой системе использовалась СУБД, иногда встречаются творения, использующие текстовые файлы для хранения данных (при миграции одной из таких систем автору пришлось писать специальный драйвер для доступа к такой базе данных).

Пожалуй, единственным положительным моментом является накопленный опыт по формированию требований к вновь разрабатываемой ИС. С другой стороны, опыт общения со старой системой может стать существенным тормозом при внедрении нового продукта. Чаще всего это возникает из-за различий построения визуального интерфейса и используемых функциональных клавиш для выполнения некоторых операций. Так, часть функциональных клавиш может быть зарезервирована операционной системой для выполнения некоторых действий. Типичным примером является применение клавиши “Enter” для перехода к следующему элементу редактируемой формы в старых ИС под DOS. В графических интерфейсах обычно для этих целей применяется клавиша “Tab”. В результате, мы получаем жесткое противодействие со стороны пользователей при внедрении новой версии продукта. Конечно, можно эмулировать поведение UI (User Interface) интерфейса старой системы, но делать это лучше всего опционально. Т.е. ввести возможность настройки поведения системы в модуле конфигурирования ИС, а по умолчанию использовать настройки соответствующие текущей операционной системе. В противном случае, вновь разработанный продукт будет труден в освоении новыми пользователями, которые ожидают поведения программы в соответствии с текущими стандартами.

Что же касается работы с хранимыми данными старой системы, то тут положение еще хуже. Наиболее тяжелые последствия будет иметь решение руководства использовать часть модулей старой системы. Например, когда перед нами стоит задача разработать новую версию складского учета, а решением остальных задач (бухучет и т.д.) пока будет заниматься старая версия ИС. В данном режиме работы встает проблема миграции данных в «реальном» режиме времени. Накладные расходы, по поддержанию работы всех модулей в целом могут превысить затраты на разработку новой версии всех модулей. Причем затраты могут отличаться на порядки, с учетом возможных потерь от недочетов старой системы и ошибок при обмене и преобразовании данных. Так что следует тщательно оценить состояние старой ИС и целесообразности. И что самое интересное, на практике данная проблема обычно не затрагивается, вплоть до возникновения: “Вот создадим новую систему, а потом и будем заниматься стыковкой с другим программным обеспечением и мигрировать данные”.

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

  • Анализ форматов данных структуры старой базы данных и новой, подготовка плана миграции и преобразования данных;
  • Определение взаимосвязей между таблицами (иерархии объектов);
  • Определение последовательности закачки данных в соответствии с иерархией зависимостей. Иногда, но не всегда (например, когда новая версия базы данных уже находится в эксплуатации) можно не учитывать взаимосвязи, а просто отключить все внешние ключи перед миграцией и пересоздать их после завершения всех манипуляций с данными;
  • Выполнение скрипта по изменению объектов в новой версии базы данных;
  • Непосредственная перекачка данных с необходимыми преобразованиями “на лету”;
  • Выполнение скрипта для восстановления отключенных индексов, дополнительных преобразований и т.д. после завершения процедуры миграции данных.

Самым простым вариантом обычно является создание промежуточной программы. Она должна связываться с исходной и целевой базами данных, и выполнять нужные преобразования.

Рис. 1. Вариант с промежуточной программой для миграции данных


Существенным недостатком данного решения может стать сетевая нагрузка при передаче данных. Если объем данных существенен, то сетевой обмен может сильно сказаться на производительности.

Более выгодным решением может быть предварительная загрузка старых данных во временные таблицы новой СУБД. Современные СУБД (например, Oracle) обычно содержат специальные утилиты, которые позволяют производить очень быструю закачку внешних данных различных форматов. Непосредственно модуль миграции пишется встроенными в СУБД процедурными языками (например, PL/SQL или java). Можно существенно повысить скорость выполнения процедуры миграции за счет того, что встроенные языки программирования работают в “родной” среде, оптимизированы под целевую СУБД и нет накладных расходов на обмен данными по сети.

Рис. 2. Вариант миграции данных средствами СУБД


Из практического опыта написания таких программ хочется обратить внимание на использование пакетных SQL методов, которые поддерживаются большинством СУБД и языками программирования (например, методы addBatch() и executeBatch() в java). Выполнение одного оператора добавления INSERT или обновления UPDATE для массива данных пачками по 100 - 200 записей дает существенный выигрыш производительности, в сравнении с выполнением данного оператора поочередно в цикле для каждой записи.

Последнее обновление: 31.10.2015

Нередко возникает ситуация, когда модель меняется. Например, мы решили внести в нее новые свойства. Но при этом у нас уже имеется существующая база данных, в которой есть какие-то данные. И чтобы без потерь обновить базу данных ASP.NET MVC предлагает нам такой механизм как миграции. Например, у нас есть простая модель User:

Public class User { public int Id { get; set; } public string Name { get; set; } }

Соответсвенно есть контекст данных, через который мы работаем с бд:

Users { get; set; } }

И допустим, у нас есть вся инфраструктура для работы с этой моделью - представления, контроллеры, и у нас есть уже в базе данных несколько объектов данной модели. Но в какой-то момент мы решили изменить модельную базу приложения. Например, мы добавили еще одно поле в модель User:

Public class User { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }

Кроме того, мы решили добавить еще одну модель, например:

Public class Company { public int Id { get; set; } public string Name { get; set; } }

Таким образом, контекст данных у нас уже меняется следующим образом:

Public class UserContext: DbContext { public UserContext() : base("DefaultConnection") { } public DbSet Users { get; set; } public DbSet Companies { get; set; } }

Мы можем добавить в представления для модели User дополнительное поле для свойства Age, можем создать контроллер и представления для новой модели, но при попытке добавить новый объект в бд, мы будем получать ошибку:

Контекст данных изменился, и теперь нам надо провести миграцию от старой схемы базы данных к новой. И первым делом найдем внизу Visual Studio окно Package Manager Console, введем в нем команду: enable-migrations и нажмем Enter:

После выполнения этой команды Visual Studio в проекте будет создана папка Migrations, в которой можно найти файл Configuration.cs . Этот файл содержит объявление одноименного класса Configuration, который устанавливает настройки конфигурации:

Namespace MigrationApp.Migrations { using System; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Linq; internal sealed class Configuration: DbMigrationsConfiguration { public Configuration() { AutomaticMigrationsEnabled = false; ContextKey = "MigrationApp.Models.UserContext"; } protected override void Seed(MigrationApp.Models.UserContext context) { } } }

В методе Seed можно проинициализировать базу данных начальными данными. Теперь нам надо создать саму миграцию. Там же в консоли Package Manager Console введем команду:

PM> Add-Migration "MigrateDB"

После этого Visual Studio автоматически сгенерирует класс миграции:

Namespace MigrationApp.Migrations { using System; using System.Data.Entity.Migrations; public partial class MigrateDB: DbMigration { public override void Up() { CreateTable("dbo.Companies", c => new { Id = c.Int(nullable: false, identity: true), Name = c.String(), }) .PrimaryKey(t => t.Id); AddColumn("dbo.Users", "Age", c => c.Int(nullable: false)); } public override void Down() { DropColumn("dbo.Users", "Age"); DropTable("dbo.Companies"); } } }

В методе Up с помощью вызова метода CreateTable создается таблица "dbo.Companies" и производится ее настройка: создание столбцов, установка ключей. И также добавляется новый столбец Age в уже имеющуюся таблицу. Метод Down удаляет столбец и таблицу на случай, если они существуют. Фактически эти методы равнозначные выражению ALTER в языке SQL, которое меняет структуру базы данных и ее таблиц.

И в завершении чтобы выполнить миграцию, применим этот класс, набрав в той же консоли команду:

PM> Update-Database

После этого, если мы посмотрим на состав базы данных, то увидим, что к ней были применены изменения в соответствии с выполненной миграцией:

Итак, миграция выполнена, и мы можем уже использовать обновленные модели и контекст данных.

Отрасль PLM развивается уже более десяти лет и наступил тот момент, когда предприятия, опробовав решения, выбранные изначально, вполне резонно решают сменить существующую PLM на другую, либо существенно изменить конфигурацию текущей. И тут возникает вопрос миграции данных PLM из старой системы в новую. Как мы знаем, даже трансляция самих геометрических данных является непростой и неоднозначно решаемой задачей, миграция данных PLM – еще более сложный и пока малоизвестный процесс.

Как это бывает
Выбор новой системы PLM был сделан, команда руководителей с облегчением празднует результат сложных усилий этого выбора. На деле, только теперь начинается настоящая работа, планирование и осуществление миграции данных из существующих систем в новую целевую платформу PLM. Существующие данные компании содержат значительную часть интеллектуальной собственности (ИС) и, следовательно, конкурентные преимущества и капитал компании. Успех внедрения новой системы в значительной степени зависит от выполнения эффективной миграции существующих данных, интеллигентно, качественно и своевременно.

Этот сценарий регулярно повторяется в том или ином виде по всему миру и в любой отрасли. С быстрыми темпами совершенствования технологий, усилением конкурентного давления, приводит к тому, что многие компании постоянно оценивают их PLM-решения и проводят улучшения. Решение может быть вызвано признанием того, что текущее решение, или, чаще, его техническое обслуживание, либо использование нескольких систем, не устраивают руководство компании. Кроме того, есть еще один общий мотив - последствия приобретений компании и осознание того, что консолидация их различных PLM решений является оправданным. Еще один сценарий – необходимость массивной перенастройки текущей платформы. Независимо от причин изменений, эффективное выполнение изменений будет зависеть от успешной миграции существующих данных на новую платформу.

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

После того как данные, которые подлежат миграции были идентифицированы, необходимо разработать и исполнить процессы проверки их правильности. Часто данные могут оказаться устаревшими, поскольку последние изменения не были внесены в более ранние версии данных. Кроме того, часто используются дублированные данные (или поддерживается в нескольких системах), требуя постоянной или периодической проверки согласованности и чистки данных. Определение полного объема данных для миграции требует использования знаний наиболее опытных сотрудников компании.

Возможно, одной из самых больших проблем миграции данных являются сроки миграции. Старые данные будут постоянно пополняться и модифицироваться, так как компания не может остановить свою работу и ждать завершения новой реализации PLM. Кроме того, в реальности коллектив, осуществляющий миграцию, имеет весьма ограниченные технические сроки для реального переключения, типично это - выходные или праздничные дни. Необходимость уложиться в доступное календарное время требует реализации алгоритмов миграции с помощью специальных инструментов, так как данные могут легко содержать в себе сотни тысяч (или даже миллионов) записей.

Пример решения
Обратимся к опыту тех, кто осуществлял и осуществляет миграцию данных PLM на регулярной основе. Одним из признанных специалистов в области миграции данных PLM является немецкая компания PRION Group , имеющая одиннадцатилетний опыт оказания таких услуг и эффективный инструментарий для их выполнения. Так как портфолио PRION включает в себя интерфейсы для наиболее распространенных PDM и унаследованными системами, из которого данные должны быть перенесены, в каждом конкретном случае у компании нет необходимости заново разработать ПО для миграции. Это позволяет быстро разработать план перехода с учетом особенностей конкретной компании и быстро выполнить миграцию, чтобы минимизировать ее воздействие на развитие продукта и производства. На рисунке ниже изображена схема типового процесса миграции данных по методологии PRION.

Наиболее существенно то, что работоспособность этой схема многократно подтверждена выполненными проектами миграции данных PLM у многочисленных клиентов PRION. Более того, неоднократные попытки произвести прямую трансляцию данных из одной системы PLM в другую доказали 100% неработоспособность такого примитивного подхода. Среди факторов, определяющих такое положение дел: сбор данных из нескольких источников, необходимость преобразования и чистки данных, их аттестации и загрузки в новую систему (ы), которые также могут быть физически распределены. Таким образом, существуют совершенно неприемлемые при переходе на новую платформу PLM.

Для снижения этих рисков, PRION разработал средства миграции, которые используют промежуточную базу данных. Данные экспортируются в промежуточную базу данных и, перед загрузкой в новую целевую платформу PLM, преобразуются в этой базе данных. Такой подход не приводит к немедленному изменению в рабочих данных и бизнес может продолжаться как обычно, в то время как разрабатываются правила и детали процесса миграции данных. Критическим фактором для успеха миграции является создание системы управления изменениями, чтобы не только отслеживать изменения, сделанные в ходе миграции самих данных, но и изменения данных, сделанные после загрузки в новую платформу PLM. Эта система управления изменениями должна поддерживать конкретные требования заказчика от самого процесса миграции до запуска новой системы в эксплуатацию в реальных условиях.

Тот факт, что PRION может использовать многие из сценариев миграции из своей обширной библиотеки, которая была разработана для бывших клиентов снижает риски миграции и снижает затраты для будущих клиентов значительно. Этот подход помогает во многих трудных сценариев миграции, особенно когда целевая система является распределенным решением.

Для получения более детальной информации об инструментах и услугах PRION рекомендую обратиться на сайт

Проблемы контроля версий баз данных и миграций между версиями уже не раз поднимались как на Хабре (, , и др.), так и в Интернете (преимущественно, англоязычном).

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

Терминология

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

Структура базы данных - совокупность всех объектов БД и статических данных. Пользовательские данные в понятие структуры БД не входят.

Версия базы данных - определенное состояние структуры базы данных. Обычно у версии есть номер, связанный с номером версии приложения.

Миграция , в данном контексте, - обновление структуры базы данных от одной версии до другой (обычно более новой).

В этом смысле термин миграция, похоже, используется во многих источниках (особенно этому поспособствовали миграции из gem"а Active Record, входящего в состав Ruby on Rails). Однако при использовании этого термина возникает двусмысленность: человек, который не знает контекста, скорее подумает, что речь идет о переносе базы данных с одной СУБД на другую (MySQL => Oracle), а то и вовсе о миграции процессов/данных между нодами кластера. Поэтому предлагаю в случаях, когда контекст неочевиден, использовать более точный термин: версионная миграция баз данных.

Зачем это нужно?

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

Версия базы данных должна соответствовать версии приложения

Итак, представьте себе следующую ситуацию: команда из нескольких программистов разрабатывает приложение, которое активно использует базу данных. Время от времени приложение поставляется в продакшн - например, это веб-сайт, который деплоится на веб-сервер.
Любому программисту в процессе написания кода приложения может понадобиться изменить структуру базы данных, а также, сами данные, которые в ней хранятся. Приведу простой пример: допустим, есть необнуляемое (not nullable) строковое поле в одной из таблиц. В этом поле не всегда есть данные, и в этом случае там хранится пустая строка. В какой-то момент вы решили, что хранить пустые строки - семантически неправильно в некоторых случаях (см. , ), а правильно - хранить NULL"ы. Для того, чтобы это реализовать, понадобятся следующие действия:

1. Изменить тип поля на nullable:

ALTER myTable CHANGE COLUMN myField myField VARCHAR (255) NULL DEFAULT NULL ;

2. Так как в этой таблице на продакшн БД уже наверняка есть пустые строки, вы принимаете волевое решение и трактуете их как отсутствие информации. Следовательно, нужно будет заменить их на NULL:
UPDATE myTable SET myField = NULL WHERE myField = "" ;

3. Изменить код приложения так, чтобы при получении из БД данных, хранящихся в этом поле, он адекватно реагировал на NULL"ы. Записывать в это поле тоже теперь нужно NULL"ы вместо пустых строк.

Из пункта 3 можно видеть, что приложение и база данных - неразрывные части одного целого. Это означает, что при поставке новой версии приложения в продакшн, нужно обязательно обновлять и версию базы данных, иначе приложение попросту не сможет правильно работать. В данном примере, если до новой версии будет обновлено только приложение, то в какой-то момент произойдет вставка NULL в необнуляемое поле, а это очевидная ошибка.

Таким образом, обновление версии приложения требует корректной версионной миграции базы данных .

Так ли это просто?

Осознав, что паритет версий БД и приложения необходим, вам нужно удостовериться, что миграции БД до нужной версии всегда будут выполняться правильно. Но в чём здесь проблема? Ведь, на первый взгляд, сложного здесь ничего нет!

Тут снова обратимся к живому примеру. Допустим, программисты в процессе разработки записывают свои изменения структуры и данных БД в отдельный файл в виде SQL-запросов (как DDL -, так и DML -запросов). А при каждом деплое последней версии приложения вы одновременно обновляете до последней версии и базу данных, выполняя запросы из того самого SQL-файла… Но погодите, с какой версии вы обновляете БД до последней версии? «С прошлой»? Но так ли хорошо вы помните, что конкретно из себя представляла прошлая версия (её выпустили 2 месяца назад)? Если нет, то как вы собрались её обновлять? Ведь без точной информации о состоянии структуры и данных выполнить корректную миграцию невозможно: если вы непредумышленно выполните запросы, которые уже когда-то выполнялись, это может привести к потере данных или нарушению их целостности.
Простой пример - замена паролей на их MD5-суммы. Если повторно выполнить такой запрос, то данные можно будет восстановить только из бэкапа. Да и вообще, любые UPDATE "ы, DELETE "ы, и даже INSERT "ы, выполненные повторно, могут привести к крайне нежелательным последствиям. Не говоря уже о несвоевременных TRUNCATE "ах и DROP "ах (хотя такие случаи намного менее вероятны).
Кстати говоря, с этой точки зрения, недовыполнить - не меньшая опасность для работоспособности приложения, чем перевыполнить.

Таким образом, можно сделать вывод, что в процессе версионной миграции все запросы должны выполняться только один раз и, к тому же, в правильной последовательности . Последовательность важна потому, что одни изменения могут зависеть от других (как в примере с обнуляемым полем).

Общие принципы версионной миграции

В предыдущем разделе мы выделили важные критерии, которые показывают, что же требуется от процесса версионной миграции. Это:
  • единоразовое выполнение каждого изменения (SQL-запроса);
  • строго предустановленный порядок изменений.
Теперь выделим более практические критерии, чтобы понять, чего требовать от самого процесса создания и хранения миграций. На мой взгляд, для большинства команд разработчиков будет важно:
  • чтобы любую версию базы данных можно было обновить до любой (обычно, самой последней) версии;
  • чтобы набор SQL-запросов, реализующих миграцию между любыми двумя версиями, можно было получить как можно быстрее и проще;
  • чтобы всегда можно было создать с нуля базу данных со структурой самой последней версии. Это очень полезно как в процессе разработки и тестирования, так и при развертывании нового продакшн-сервера;
  • чтобы, в случае работы над разными ветками, при последующем их слиянии ручное редактирование файлов БД было сведено к минимуму;
  • чтобы откатить БД на более раннюю версию было так же просто, как и обновить на более новую.

Основание миграции

Как оказалось, у большинства подходов есть общий принцип: им необходимо основание (baseline) - некоторое эталонное состояние БД, от которого можно отталкиваться. Эта концепция довольно хорошо описана в статье «Versioning Databases – The Baseline» Скотта Аллена.

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

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

Этот метод хорошо описан в статье «Versioning Databases – Change Scripts» все того же Скотта Аллена. Схожий подход также описан в статье «Managing SQL scripts and continuous integration» Майкла Бэйлона.

Структура файлов

Пример того, как в этом случае может выглядеть папка с файлами-миграциями:
Database
|- Baseline.sql
|- 0001.03 .01.sql
|- 0002.03 .01.sql
|- 0003.03 .01.sql
|- 0004.03 .02.sql
|- 0005.03 .02.sql
|- 0006.03 .02.sql
"- 0007.03 .02.sql

В этом примере в папке хранятся все файлы, созданные при разработке версии 03 . Впрочем, папка может быть и общей для всех версий приложения.

В любом случае, самый первый файл, который появится в такой папке, - основание (Baseline.sql). После этого любое изменение в БД сабмиттится в репозиторий в виде нового файла-миграции с именем вида [номер файла].[версия].[подверсия].sql .

Фактически, в этом примере в имени файла содержится полный номер версии БД. То есть после выполнения файла-миграции с именем 0006 .03.02.sql база данных обновится с состояния, соответствующего версии 03.02.0005 , до версии 03.02.0006 .

Хранение истории версий

Следующий шаг - добавление в базу данных специальной таблицы, в которой будет храниться история всех изменений в базе данных.
CREATE TABLE MigrationHistory
Id INT ,
MajorVersion VARCHAR (2),
MinorVersion VARCHAR (2),
FileNumber VARCHAR (4),
Comment VARCHAR (255),
DateApplied DATETIME ,

PRIMARY KEY (Id)
)



Это всего лишь пример того, как может выглядеть таблица. При необходимости, её можно как упростить, так и дополнить.

В файле Baseline.sql в эту таблицу нужно будет добавить первую запись:

INSERT INTO
MigrationHistory (MajorVersion, MinorVersion, FileNumber, Comment, DateApplied)
VALUES ("03" , "01" , "0000" , "Baseline" , NOW())


После выполнения каждого файла-миграции в эту таблицу будет заноситься запись со всеми данными о миграции.
Текущую версию БД можно будет получить из записи с максимальной датой.

Автоматическое выполнение миграций

Завершающий штрих в этом подходе - программа/скрипт, который будет обновлять БД с текущей версии до последней.

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

На такой скрипт также возлагается задача добавления записей о выполненных миграциях в таблицу MigrationHistory.

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

Плюсы, минусы, выводы

Быстрое и удобное выполнение миграции до последней версии;
Механизм нумерации версий. Номер текущей версии хранится прямо в БД;
Для максимального удобства нужны средства автоматизации выполнения миграций;
Неудобно добавлять комментарии к структуре БД. Если их добавлять в Baseline.sql, то в следующей версии они пропадут, т.к. основание будет сгенерировано с нуля вновь, в качестве дампа новой версии структуры. Вдобавок, такие комментарии будут быстро устаревать;
Возникают проблемы в процессе параллельной разработки в нескольких ветках репозитория. Так как нумерация файлов-миграций - последовательная, то под одинаковыми номерами в разных ветках могут возникнуть файлы с разными DDL-/DML-запросами. Как следствие, при слиянии веток придется либо вручную редактировать файлы и их последовательность, либо же в новой, «слитой» ветке начинать с нового Baseline.sql, учитывающего изменения из обеих веток.

Этот метод в различных формах довольно широко распространен. К тому же, он легко поддается упрощению и модификации под нужды проекта.
В интернете можно найти готовые варианты скриптов по инкрементному выполнению миграций и встроить в свой проект.

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

Этот метод описан в статье «Bulletproof Sql Change Scripts Using INFORMATION_SCHEMA Views» Фила Хэка. Описание схожего подхода также изложено в ответе на этот вопрос на StackOverflow.

Под идемпотентностью понимается свойство объекта оставаться неизменным при повторной попытке его изменить.
В тему вспоминается смешная сцена из «Друзей»:)

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

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

CREATE TABLE IF NOT EXISTS myTable
id INT (10) NOT NULL ,

PRIMARY KEY (id)
);

Благодаря ключевой фразе IF NOT EXISTS , MySQL попытается создать таблицу только в том случае, если таблицы с таким именем еще не существует. Однако такой синтаксис доступен не во всех СУБД; к тому же, даже в MySQL его можно использовать не для всех команд. Поэтому рассмотрим более универсальный способ:
IF NOT EXISTS
SELECT *
FROM information_schema.tables
WHERE table_name = "myTable"
AND table_schema = "myDb"
THEN
CREATE TABLE myTable
id INT (10) NOT NULL ,
myField VARCHAR (255) NULL ,
PRIMARY KEY (id)
);
END IF ;

В последнем примере роль параметра условного выражения играет запрос, который проверяет, существует ли таблица myTable в базе данных с именем myDb . И только в том случае, если таблица отсутствует, произойдет, собственно, ее создание. Таким образом, приведенный запрос является идемпотентным.

Стоит отметить, что в MySQL по какой-то причине запрещено выполнять DDL -запросы внутри условных выражений. Но этот запрет легко обойти - достаточно включить все подобные запросы в тело хранимой процедуры:

DELIMITER $$

CREATE PROCEDURE sp_tmp() BEGIN

IF NOT EXISTS
--
-- Условие.
--
THEN
--
-- Запрос, изменяющий структуру БД.
--
END IF ;

END ;
$$

CALL sp_tmp();

DROP PROCEDURE sp_tmp;

Что за птица такая - information_schema?

Полную информацию о структуре базы данных можно получить из специальных системных таблиц, находящихся в базе данных с именем information_schema . Эта база данных и ее таблицы - часть стандарта SQL-92, поэтому этот способ можно использовать на любой из современных СУБД. В предыдущем примере используется таблица information_schema.tables , в которой хранятся данные о всех таблицах. Подобным образом можно проверять существование и метаданные полей таблиц, хранимых процедур, триггеров, схем, и, фактически, любых других объектов структуры базы данных.

Полный перечень таблиц с подробной информацией об их предназначении можно посмотреть в тексте стандарта . Краткий перечень можно увидеть в уже упоминавшейся выше статье Фила Хэка . Но самый простой способ, конечно же, - просто открыть эту базу данных на любом рабочем сервере БД и посмотреть, как она устроена.

Пример использования

Итак, вы знаете, как создавать идемпотентные SQL-запросы. Теперь рассмотрим, как этот подход можно использовать на практике.

Пример того, как в этом случае может выглядеть папка с sql-файлами:

Database
|- 3.01
| |- Baseline.sql
| "- Changes.sql
"- 3.02
|- Baseline.sql
"- Changes.sql

В этом примере для каждой минорной версии базы данных создается отдельная папка. При создании каждой новой папки генерируется основание и записывается в Baseline.sql. Затем в процессе разработки в файл Changes.sql записываются все необходимые изменения в виде идемпотентных запросов.

Предположим, в процессе разработки в разное время программистам понадобились следующие изменения в БД:
a) создать таблицу myTable;
b) добавить в нее поле newfield;
c) добавить в таблицу myTable какие-то данные.

Все три изменения написаны так, чтобы не выполняться повторно. В результате, в каком бы из промежуточных состояний не находилась база данных, при выполнении файла Changes.sql всегда будет выполнена миграция до самой последней версии.

К примеру, один из разработчиков создал на своей локальной копии БД таблицу myTable, записал изменение a) в хранящийся в общем репозитории кода файл Changes.sql, и на какое-то время забыл о нём. Теперь, если он выполнит этот файл на своей локальной БД, изменение a) будет проигнорировано, а изменения b) и c) будут применены.

Плюсы, минусы, выводы

Очень удобное выполнение миграций с любой промежуточной версии до последней - нужно всего лишь выполнить на базе данных один файл (Changes.sql);
Потенциально возможны ситуации, в которых будут теряться данные, за этим придется следить. Примером может служить удаление таблицы, и затем создание другой таблицы с тем же именем. Если при удалении проверять только имя, то обе операции (удаление и создание) будут происходить каждый раз при выполнении скрипта, несмотря на то, что когда-то уже выполнялись;
Для того, чтобы изменения были идемпотентными, нужно потратить больше времени (и кода) на их написание.

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

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

Отдельных статей, посвященных этому подходу, я, к сожалению, не нашел. Буду благодарен за ссылки на существующие статьи, если таковые имеются. UPD: В своей статье Absent рассказывает о своем опыте реализации схожего подхода при помощи самописной diff-утилиты.

Основная идея этого метода отражена в заголовке: структура БД - такой же исходный код, как код PHP, C# или HTML. Следовательно, вместо того, чтобы хранить в репозитории кода файлы-миграции (с запросами, изменяющими структуру БД), нужно хранить только актуальную структуру базы данных - в декларативной форме.

Пример реализации

Для простоты примера будем считать, что в каждой ревизии репозитория всегда будет только один SQL-файл: CreateDatabase.sql. В скобках замечу, что в аналогии с исходным кодом можно пойти еще дальше и хранить структуру каждого объекта БД в отдельном файле. Также, структуру можно хранить в виде XML или других форматов, которые поддерживаются вашей СУБД.

В файле CreateDatabase.sql будут храниться команды CREATE TABLE , CREATE PROCEDURE , и т.д., которые создают всю базу данных с нуля. При необходимости изменений структуры таблиц, эти изменения вносятся непосредственно в существующие DDL-запросы создания таблиц. То же касается изменений в хранимых процедурах, триггерах, и т.д.

К примеру, в текущей версии репозитория уже есть таблица myTable, и в файле CreateDatabase.sql она выглядит следующим образом:

CREATE TABLE myTable
id INT (10) NOT NULL ,
myField VARCHAR (255) NULL ,
PRIMARY KEY (id)
);

Если вам нужно добавить в эту таблицу новое поле, вы просто добавляете его в имеющийся DDL-запрос:
CREATE TABLE myTable
id INT (10) NOT NULL ,
myField VARCHAR (255) NULL ,
newfield INT(4) NOT NULL ,
PRIMARY KEY (id)
);

После этого измененный sql-файл сабмиттится в репозиторий кода.

Выполнение миграций между версиями

В этом методе процедура обновления базы данных до более новой версии не так прямолинейна, как в других методах. Поскольку для каждой версии хранится только декларативное описание структуры, для каждой миграции придется генерировать разницу в виде ALTER -, DROP - и CREATE -запросов. В этом вам помогут автоматические diff-утилиты, такие, как Schema Synchronization Tool, входящая в состав SQLyog , TOAD , доступный для многих СУБД,
Loading...Loading...