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

Вы написали скрипт миграции. Он выглядит корректно. Логика верна. Вы запускаете его на стейджинге — всё проходит успешно. Но когда вы запускаете его на продакшене, что-то идёт не так. Возможно, нарушается ограничение столбца. Возможно, возникает ошибка внешнего ключа. Возможно, миграция занимает 45 минут вместо ожидаемых 5, блокируя критическую таблицу и вызывая каскад таймаутов во всём приложении.

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

Что на самом деле делает сухой прогон

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

Самый распространённый способ сделать это — обернуть миграцию в транзакцию базы данных и завершить её ROLLBACK вместо COMMIT. Если у вас есть скрипт, который добавляет новый столбец и заполняет его из другой таблицы, вы оборачиваете всё в BEGIN TRANSACTION ... ROLLBACK. Если ошибка возникает на полпути, транзакция автоматически отменяется, и база данных возвращается в исходное состояние. Если ошибки нет, вы всё равно откатываетесь вручную. Вы не стремитесь применить изменение. Вы ищете подтверждение, что скрипт корректен.

Вот конкретный пример того, как это выглядит в SQL:

BEGIN TRANSACTION;

-- Пример миграции: добавить новый столбец и заполнить его
ALTER TABLE users ADD COLUMN last_login_at TIMESTAMP;

UPDATE users
SET last_login_at = NOW()
WHERE last_login_at IS NULL;

-- Проверить, что данные выглядят корректно перед откатом
SELECT id, email, last_login_at FROM users LIMIT 10;

-- Откатить транзакцию, оставив базу данных без изменений
ROLLBACK;

Что сухой прогон говорит вам помимо синтаксических ошибок

Проверка на синтаксические ошибки или нарушения ограничений — очевидное преимущество. Но сухой прогон даёт гораздо больше полезной информации.

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

Без сухого прогона вы гадаете. С сухим прогоном у вас есть данные для принятия обоснованного решения.

Где выполнять сухой прогон

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

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

Как читать результаты сухого прогона

Чистый вывод без ошибок и предупреждений обнадёживает. Но не останавливайтесь на этом. Внимательно просмотрите логи.

Ищите строки, которые не удалось заполнить, потому что данные не соответствовали новому типу столбца. Ищите конфликты индексов. Ищите нарушения внешних ключей. Иногда сухой прогон технически успешен, но логически ошибочен. Например, перемещённые данные могут быть пустыми, потому что ваше условие WHERE было неверным. Скрипт выполнился нормально. Без ошибок. Но результат бесполезен.

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

Что сухой прогон не может гарантировать

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

Практический чек-лист перед запуском миграции

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

  • Оберните миграцию в транзакцию и выполните её с ROLLBACK
  • Проверьте время выполнения и длительность блокировок
  • Убедитесь, что количество затронутых строк соответствует ожиданиям
  • Выполните запросы к изменённым таблицам внутри транзакции, чтобы подтвердить корректность данных
  • Просмотрите логи на предмет нарушений ограничений, конфликтов индексов или несоответствия типов
  • Если миграция занимает слишком много времени или вызывает слишком сильные блокировки, спланируйте альтернативную стратегию

Конкретный вывод

Сухой прогон — это не лишний шаг. Это шаг, который отделяет уверенный деплой от стрессового. Выполните миграцию в транзакции. Откатите её. Проверьте результаты. Затем решите, готовы ли вы фиксировать изменения. Ваши продакшен-данные скажут вам спасибо.