Обновление схем баз данных
В этом выпуске мы говорили о том, как эволюционно изменять схему базы данных по ходу роста продукта. В гостях у нас был Василий Васильков из 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 - фреймворк для миграций. Тут можно подсмотреть, как можно сделать похожее в своем продукте
Ну и на сладкое, пара интересных подходов к реляционным базам: