Перевод статьи «Database versioning best practices», опубликованной на сайте enterprisecraftsmanship.com.

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

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

Давайте рассмотрим лучшие подходы к управлению версиями баз данных.

Управление версиями баз данных: проблема


Когда вы работаете над проектом в одиночку, который еще не выпущен в production, то не возникает таких проблем, как проблема управления версиями базы данных. Вы изменяете схему данных так, как вы хотите и это всегда работает.

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

Выглядит знакомо? Бьюсь об заклад у вас бывали такие ситуации, более чем единожды. У меня, кончено, бывали.

Лучшие подходы к к управлению версиями баз данных


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

Хорошо, так что же это за лучшие практики для версионирования баз данных?

Best practice #1: мы должны относиться к базе данных приложения и справочным данных, как к обычному коду. Это значит, что мы должны хранить и схему, и справочные данные в системе управления версиями.

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

Best practice #2: мы должны хранить все изменения в схеме базы данных и справочных данных в явном виде. Это означает, что для каждой модификации мы должны создать отдельный сценарий SQL с изменениями. Если модификация влияет как на схему, так и на справочные данные, они должны быть отражены в одном сценарии.

image

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

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

Best practice #3: каждый файл SQL скрипта должен быть неизменным после развертывания в production или промежуточную среды.

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

Best practice #4: все изменения в схеме и справочных данных в базах данных должны быть применены через скрипты. Ни один из них может быть применен вручную.

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

Best practice #5: каждый разработчик в команде должен иметь свой экземпляр базы данных.

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

Часто программисты делают несовместимые изменения, так что это хорошая идея, чтобы каждый программист имел отдельный экземпляр базы данных, воизбежании таких коллизий. Если разработчики делают изменения какой-то части схемы БД одновременно, то такие конфликты могут быть разрешены с помощью системы управления версиями, как конфликты в C # / Java и т.д.

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

Best practice #6: версии базы данных должны храниться в самой базе данных. Я, как правило, создаю отдельную таблицу с названием «Settings» и храню версию там. Не используйте сложные обозначения типа «x.y.z» для номеров версий, просто используйте целое число.

Каковы преимущества такого подхода?


Так какие же преимущества нам дают лучшие подходы к версионированию баз данных?

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

Это особенно полезно, когда у вас нет единой production базы данных, но каждый клиент имеет свой собственный экземпляр базы данных. Управление версией БД в таких условиях может стать адом, если вы не использовать правильные техники управления версиями.

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

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

Описанный в этом посте подход применим, даже если вы не следовали ему с самого начала. Чтобы использовать это на практике нужно просто создать первоначальный сценарий схемы базы данных, который вы имеет на данный момент в production и можете постепенно начать изменять его с этого момента. Текущая версия, должна стать версией #1, с которой вы можете двигаться дальше, используя подходы, которые мы обсуждали выше.

Комментарии (19)


  1. MaximChistov
    31.08.2015 10:34
    +3

    Это означает, что для каждой модификации мы должны создать отдельный сценарий SQL с изменениями

    Какая нафиг Best Practice? Как автогенерированный write only скрипт позволит отслеживать, какие обновления уже были накачены, а какие нет? Такое надо делать кодом.
    Веселее всего когда приходится накатывать апгрейды на базу от версии, отстающей от нынешней на пару цифр, там такие замечательные баги вылезают, особенно в ORM.


    1. drakmail
      31.08.2015 11:20
      -2

      Миграции в рельсах/django решают эти проблемы


    1. relgames
      31.08.2015 11:55

      «Best practice #6: версии базы данных должны храниться в самой базе данных»
      Никто руками скрипты не накатывает. Для Java, к примеру, есть flyway


  1. WeslomPo
    31.08.2015 11:16
    +6

    Что-то я не услышал волшебного слова «Миграция» в этом переводе. Откройте для себя новый замечательный инструмент, и вам не захочется переводить капитанские статьи. Сам перевод недурственен.


    1. Evengard
      31.08.2015 12:00

      Мб немного не в тему, но всё же. Кто знает как подружить EF6+npgsql+Постгрес с миграциями? (.NET)


      1. alemiks
        31.08.2015 12:43
        +2

        А что у вас не получилось? Действия те же самые, что и в случае с mssql, только в конструкторе класса Configuration нужно

        SetSqlGenerator("Npgsql", new NpgsqlMigrationSqlGenerator());
        


    1. alemiks
      31.08.2015 12:47
      +1

      Скорее всего в статье нет слова «миграция» потому, что в названии сайта есть слово «enterprise». А это значит, что к одной БД может быть подключено десятки (а в случае запущенной стадии энтерпрайза и сотни) приложений. В каком из них делать миграции?


      1. lair
        31.08.2015 12:59
        +1

        В том, которое является основным стейкхолдером конкретного компонента БД.

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


    1. Delphinum
      31.08.2015 12:50
      +1

      Проблема именно в терминологии, или есть реальные отличия между инструментом «Миграции» и тем, что предлагается в статье?


      1. WeslomPo
        31.08.2015 14:05
        +1

        То что описывается в статье, на мой взгляд, и есть миграции. Это как написать статью о том как правильно вкручивать сотни шурупов не упоминая шуруповёрт.


        1. Delphinum
          31.08.2015 14:30

          Видимо предлагаемая в статье книга была написана до появления этого термина )


          1. WeslomPo
            31.08.2015 14:31

            У меня тоже возникли именно такие подозрения ;).


  1. MacIn
    31.08.2015 13:45
    +1

    Versioning — управление версиями.

    Best practice #6: версии базы данных должны храниться в самой базе данных. Я, как правило, создаю отдельную таблицу с названием «Settings» и храню версию там. Не используйте сложные обозначения типа «x.y.z» для номеров версий, просто используйте целое число.

    У нас в mysql версия таблицы прописывается в комментарии к таблице.


    1. dipiash
      31.08.2015 18:20

      Versioning — управление версиями.

      Спасибо за уточнение. Поправил.


  1. kuzemchik
    31.08.2015 16:08
    +1

    Посмотрите на Liquibase.
    Там есть все что вы описали + много другого полезного.


    1. eugenius_nsk
      31.08.2015 16:12

      Синхронно))


  1. eugenius_nsk
    31.08.2015 16:11
    +1

    Best practice #0: использовать Liquibase.


  1. savostin
    31.08.2015 18:24

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