7 мин

Автоматические миграции PostgreSQL в продакшене

Разбираем, когда миграции PostgreSQL в продакшене можно запускать автоматически, а когда нужны одобрение, проверка блокировок, backup и откат.

Автоматические миграции PostgreSQL в продакшене

Автоматически применять миграции PostgreSQL в продакшене можно, но право на запуск должно зависеть от содержания конкретной миграции, а не от того, кто ее написал. AI-среда может подготовить SQL, проверить его и выполнить безопасный класс изменений. Она не должна получать безусловное право менять рабочую базу.

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

Автозапуск допустим только для узкого класса изменений

Разрешать автоматический запуск стоит для повторяемых, ограниченных по времени и совместимых с текущей версией приложения операций. Белый список должен быть коротким. Чем шире формулировка вроде «обычные DDL-изменения», тем быстрее в нее попадет команда, которая удерживает блокировку дольше окна доступности.

В типичный автоматический класс входят создание новой таблицы без тяжелого заполнения, добавление nullable-столбца без значения по умолчанию, создание отдельного типа или последовательности, а также добавление индекса через CREATE INDEX CONCURRENTLY. Последняя операция требует отдельного обработчика: PostgreSQL запрещает выполнять ее внутри блока транзакции, а неудачный запуск может оставить невалидный индекс.

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

Минимальная политика может выглядеть так:

auto_apply:
  allow:
    - create_table_empty
    - add_nullable_column
    - create_index_concurrently
  require_manual_approval:
    - alter_column_type
    - add_not_null
    - add_foreign_key
    - drop_object
    - data_backfill
  reject:
    - unparsed_sql
    - transaction_control
    - dynamic_sql

Такая конфигурация предотвращает неприятную подмену понятий: «модель уверена в запросе» не означает «запрос безопасен под текущей нагрузкой». Уверенность генератора вообще не должна участвовать в решении о продакшене. Решение принимают детерминированные проверки.

У каждой разрешенной операции должны быть дополнительные условия. CREATE TABLE проходит автоматически, только если в ней нет CREATE TABLE AS SELECT, внешних ключей к горячим таблицам и функций в значениях по умолчанию. ADD COLUMN проходит, только если команда не требует немедленного пересчета существующих строк. Для значения по умолчанию правила обязаны учитывать версию сервера и само выражение, а не переносить поведение одной версии PostgreSQL на другую.

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

Безопасный SQL и безопасный релиз отличаются

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

Для изменений столбца используйте схему expand and contract. Сначала добавьте новый nullable-столбец. Затем разверните код, который пишет в старый и новый столбцы, и перенесите исторические данные порциями. После проверки чтения переключите приложение на новый столбец. Ограничение NOT NULL и удаление старого столбца оставьте для отдельного релиза.

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

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

Отдельно помечайте необратимые смысловые изменения. DROP COLUMN можно откатить синтаксически только созданием пустого столбца, но данные уже исчезли. Преобразование значений с потерей точности тоже нельзя честно назвать обратимым, даже если инструмент сгенерировал down-скрипт.

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

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

Блокировки надо измерять до запуска

Перед применением DDL автомат должен определить требуемый режим блокировки, размер затронутых таблиц и наличие долгих транзакций. PostgreSQL прямо описывает режимы блокировок в разделе Explicit Locking своей документации. Многие варианты ALTER TABLE берут ACCESS EXCLUSIVE, а этот режим конфликтует со всеми режимами табличных блокировок.

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

Перед запуском соберите хотя бы такой снимок:

SELECT
  a.pid,
  now() - a.xact_start AS xact_age,
  a.state,
  left(a.query, 160) AS query
FROM pg_stat_activity AS a
WHERE a.datname = current_database()
  AND a.xact_start IS NOT NULL
ORDER BY a.xact_start;

Ожидаемый результат имеет форму pid | xact_age | state | query. Политика должна задать предел возраста транзакции, а не поручать модели решить, что выглядит «достаточно старым». Значение зависит от сервиса: у пакетной обработки и API разные нормальные профили.

Для самой сессии миграции установите жесткие пределы:

SET lock_timeout = '3s';
SET statement_timeout = '15min';

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

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

Планировщик также должен учитывать реплики. DDL может быстро завершиться на основном сервере, а связанный backfill создаст поток WAL и увеличит задержку чтения на реплике. Если приложение читает с реплик, условие завершения включает возврат задержки к принятому порогу. Сам факт успешного ответа основной базы еще не означает, что релиз закончен.

Не завершайте проверку после получения блокировки. Сразу перед DDL запишите блокирующие и ожидающие процессы из pg_locks вместе с pg_stat_activity, а во время длительной операции следите за очередью. Автомат должен отменить свою сессию по заранее заданному условию, пока оператор не вынужден аварийно завершать пользовательские подключения.

Некоторые команды всегда требуют ручного одобрения

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

Я бы отправлял человеку следующие случаи:

  • DROP TABLE, DROP COLUMN, TRUNCATE и удаления типов;
  • ALTER COLUMN TYPE, особенно с выражением USING;
  • добавление NOT NULL, внешнего ключа или проверочного ограничения к существующим данным;
  • любой backfill без ограничения размера порции и паузы;
  • расширения PostgreSQL, функции с повышенными правами и динамический SQL.

Одобрение не должно сводиться к просмотру сгенерированного текста. Карточка решения обязана показывать SQL, оценку числа строк, требуемый режим блокировки, результат репетиции, план резервного копирования и точку невозврата. Если интерфейс прячет это за зеленым статусом «проверено AI», человек одобряет бренд, а не изменение.

Для ограничений PostgreSQL дает полезную двухфазную технику. Например, внешний ключ или CHECK можно добавить как NOT VALID, а затем проверить отдельной командой VALIDATE CONSTRAINT. Документация ALTER TABLE поясняет, что первая команда пропускает проверку старых строк, хотя новые записи уже должны соблюдать ограничение. Это уменьшает цену начальной блокировки, но не отменяет проверку нагрузки перед валидацией.

С NOT NULL тоже не стоит торопиться. Сначала найдите и устраните NULL, затем докажите условие через валидированное ограничение, и только после этого меняйте атрибут столбца в подходящем окне. Конкретное поведение и оптимизации зависят от версии PostgreSQL, поэтому политика должна хранить версию сервера как входной параметр.

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

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

Репетиция должна воспроизводить объем и конкуренцию

Проверьте SQL в исходниках
Экспортируйте созданный TakProsto код и проверьте миграции по правилам своей базы.

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

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

Для индекса есть особая ловушка. Руководство PostgreSQL по CREATE INDEX CONCURRENTLY объясняет, что такой индекс строится несколькими проходами и ждет транзакции, которые могут влиять на индексируемые строки. Команда меньше мешает записи, но делает больше работы и занимает больше времени. Ее нельзя запускать внутри транзакционного блока.

После сбоя проверяйте состояние:

SELECT
  c.relname,
  i.indisvalid,
  i.indisready
FROM pg_index AS i
JOIN pg_class AS c ON c.oid = i.indexrelid
WHERE c.relname = 'idx_orders_customer_created';

Если indisvalid равен false, индекс не обслуживает обычные запросы как готовый индекс, но занимает место и может добавлять расходы на обновления. Автомат не должен просто повторять ту же команду. Он фиксирует невалидный объект, предлагает удалить его конкурентно, если это допустимо для версии и состояния, а повторный запуск проводит как новую операцию.

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

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

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

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

Резервная копия нужна с доказанной точкой восстановления

Фраза «резервная копия включена» не дает права запускать опасную миграцию. Перед изменением нужно знать, до какой точки можно восстановиться, где лежат базовая копия и архив WAL, кто имеет доступ к восстановлению и сколько заняла последняя проверка процедуры.

Логическая копия через pg_dump полезна для переноса объектов и выборочного восстановления, но она не заменяет план восстановления рабочего кластера до точки во времени. Для point-in-time recovery PostgreSQL использует базовую резервную копию и непрерывную архивацию WAL. Именно этот механизм нужен, когда требуется вернуть состояние базы непосредственно перед миграцией.

Проверка перед ручным одобрением должна содержать конкретные поля:

{
  "migration_id": "2026_07_27_001_add_order_state",
  "backup_completed_at": "2026-07-27T01:42:10Z",
  "restore_point": "before_2026_07_27_001",
  "wal_archive_status": "ok",
  "restore_drill_age_days": 18,
  "approved_by": null
}

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

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

У резервной копии есть неприятная цена: восстановление возвращает весь кластер или выбранный контур назад, а не отменяет одну строку DDL без последствий для новых записей. Если после миграции пользователи успели создать заказы, полный возврат к прошлой точке потеряет эти изменения. Поэтому backup защищает от катастрофы, но не заменяет совместимую схему и прикладной откат.

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

Перед миграцией проверьте свободное место там, где оно действительно потребуется. Создание индекса требует места для нового объекта и временной работы, а WAL хранится и передается отдельно. Резервная копия, которая заполняет последний свободный диск прямо перед DDL, повышает риск вместо его снижения.

Откат проектируют отдельно от down-скрипта

Держите откат рядом с релизом
Снимки и откат TakProsto помогают вернуть проект, если новый код не прошел проверку.

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

Для добавочного изменения лучший откат часто не трогает базу. Остановите развертывание, верните предыдущую версию приложения и оставьте новый nullable-столбец или неиспользуемую таблицу до отдельной уборки. Немедленный DROP добавляет вторую опасную миграцию в момент, когда команда уже разбирает инцидент.

Для каждого изменения сохраните таблицу решения:

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

Тестируйте успешный up и остановку в каждой длительной фазе. Для транзакционной миграции достаточно убедиться, что PostgreSQL откатил транзакцию. Для CREATE INDEX CONCURRENTLY, backfill и внешних процессов нужны проверки промежуточного состояния.

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

Задайте наблюдаемые сигналы заранее: рост ошибок записи, превышение задержки запросов, отставание реплики, срабатывание lock_timeout или нарушение контрольного запроса. Формулировка «откатить, если станет плохо» непригодна для автомата и спорна для дежурного. Для каждого сигнала укажите действие и человека, который принимает решение о восстановлении.

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

Исполнитель миграций должен иметь мало прав и один слот

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

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

SELECT pg_try_advisory_lock(741852963);

Ожидаемый результат равен true только у одного исполнителя. При false процесс завершает запуск без повторов в тесном цикле. Число в примере нужно заменить стабильным идентификатором проекта и окружения, а соединение следует удерживать до конца миграции, потому что сессионная advisory-блокировка снимается при закрытии соединения.

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

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

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

Проверьте также search_path. Миграция с неквалифицированным именем таблицы может изменить объект из неожиданной схемы, если окружения настроены по-разному. Надежнее указывать схему явно и устанавливать контролируемый search_path для сессии исполнителя.

Ворота релиза должны выдавать объяснимое решение

Начните с отдельного контура
Создайте в TakProsto небольшой серверный проект с PostgreSQL и отработайте политику миграций.

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

Пример результата проверки:

{
  "decision": "manual_approval",
  "reasons": [
    {
      "code": "ACCESS_EXCLUSIVE_ON_LARGE_TABLE",
      "object": "public.orders",
      "detail": "ALTER TABLE требует блокировку, таблица превышает автоматический порог"
    },
    {
      "code": "RESTORE_DRILL_TOO_OLD",
      "detail": "возраст последней проверки восстановления превышает политику"
    }
  ],
  "sql_sha256": "4f9d...c21a"
}

Порядок ворот имеет значение. Сначала разберите SQL и запретите неизвестные конструкции. Затем проверьте совместимость релиза, права, версию сервера и резервную копию. После этого выполните репетицию, оцените блокировки и только перед запуском повторно снимите рабочее состояние.

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

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

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

В TakProsto режим планирования можно использовать, чтобы отделить обсуждение изменения от его выполнения, а снимки, откат и деплой включить в общий план релиза. Эти возможности не отменяют проверку PostgreSQL: политика базы все равно должна опираться на SQL, блокировки, резервную копию и совместимость приложения.

Начните с запрета и расширяйте белый список по фактам

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

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

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

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

Полезная метрика на старте проста: какая доля миграций попала в каждый из трех исходов и почему. Она нужна не для цели «автоматизировать сто процентов», а чтобы найти повторяющийся безопасный класс и плохие шаблоны миграций. Если ручных решений много из-за backfill в одном файле с DDL, исправьте процесс подготовки миграций, а не ослабляйте ворота.

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

FAQ

Можно ли полностью доверить миграции PostgreSQL AI-агенту?

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

Какие миграции PostgreSQL подходят для автоматического запуска?

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

Почему ALTER TABLE может остановить работающий сервис?

Многие варианты ALTER TABLE запрашивают сильную табличную блокировку и ждут текущие транзакции. Пока DDL стоит в очереди, за ним могут накопиться обычные запросы, поэтому короткая команда иногда вызывает заметный простой.

Нужна ли ручная проверка для добавления NOT NULL?

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

Достаточно ли pg_dump перед опасной миграцией?

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

Всегда ли down-миграция возвращает базу в прежнее состояние?

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

Какой lock_timeout поставить для миграций?

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

Можно ли выполнять две миграции одновременно?

Для одного контура лучше разрешать только один исполнитель. Сессионная advisory-блокировка PostgreSQL или эквивалентный внешний замок не даст двум релизам менять схему в разном порядке.

Что проверять после CREATE INDEX CONCURRENTLY?

Проверьте pg_index.indisvalid и pg_index.indisready, а также размер и имя созданного объекта. После сбоя может остаться невалидный индекс, поэтому слепой повтор команды только добавит путаницу.

С чего начать автоматизацию миграций в существующем проекте?

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

Похожие статьи