Обновление схем баз данных

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

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

Взять хотя бы транзакции. Казалось бы, вполне невинная штука, которой учат на многих курсах и мастер-классах. Но не все знают, что долгие транзакции приводят к тому, что инструкцию "Alter Table" выполнить онлайн может быть практически невозможно из-за блокировок.

Ну или еще одна проблема – большое количество операций чтения. Поскольку чтение – это "shared access lock", за которым встает в очередь операция "alter table", имеющая "exclusive lock", то все операции записи выстраиваются за ними.

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

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

Вот один из примеров. Представьте что вам нужно добавить "наживую" новую колонку со значением по-умолчанию и ограничением на "not null". Делать "alter table" в один проход может быть очень дорого: таблицу может заблокировать на десятки минут, и ваш продакшен встанет. Вместо этого, миграция делается в 4 прохода:

  • Просто добавляется колонка, без дополнительных ограничений
  • Устанавливается значение по-умолчанию (обновления при этом не происходит)
  • Несколькими запросами делается обновление значений в колонке
  • Когда все обновлено, устанавливается констрейнт "not null"

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

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

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

К слову о коллегах… В сообществе hangops.ru постоянно находятся люди, готовые делиться опытом. Если у вас есть вопросы, задавайте их в комментариях. А если есть чем поделиться, приходите на выпуски, которые мы устраиваем каждую неделю в четверг.

Ссылки из этого выпуска:

  • Refactoring Databases: Evolutionary Database Design - Книга, которую посоветовал Артем Журбило
  • Stellar - утилита для быстрого дампа и восстановления данных из базы
  • DBMaestro - коммерческий продукт для организации своеобразного Continuous Integration баз данных
  • FlywayDB - фреймворк для миграций. Тут можно подсмотреть, как можно сделать похожее в своем продукте

Ну и на сладкое, пара интересных подходов к реляционным базам:

comments powered by Disqus