KoderKoder.ai
ЦеныДля бизнесаОбразованиеДля инвесторов
ВойтиНачать

Продукт

ЦеныДля бизнесаДля инвесторов

Ресурсы

Связаться с намиПоддержкаОбразованиеБлог

Правовая информация

Политика конфиденциальностиУсловия использованияБезопасностьПолитика допустимого использованияСообщить о нарушении

Соцсети

LinkedInTwitter
Koder.ai
Язык

© 2026 Koder.ai. Все права защищены.

Главная›Блог›Claude Code: миграции PostgreSQL — подсказки для безопасных изменений
05 дек. 2025 г.·6 мин

Claude Code: миграции PostgreSQL — подсказки для безопасных изменений

Как с помощью Claude Code готовить безопасные миграции PostgreSQL: pattern expand/contract, бэкафиллы, планы отката и что проверять в staging перед релизом.

Claude Code: миграции PostgreSQL — подсказки для безопасных изменений

Что делает изменение схемы PostgreSQL рискованным

Изменение схемы PostgreSQL выглядит простым, пока не встретится с реальным трафиком и реальными данными. Риск обычно не в самом SQL. Риск — когда код приложения, состояние базы и тайминг деплоя перестают совпадать.

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

AI‑сгенерированные миграции добавляют ещё один слой риска. Инструменты могут создать валидный SQL, который всё равно небезопасен для вашей нагрузки, объёма данных или процесса релиза. Они могут угадывать имена таблиц, не заметить долгие блокировки или смазать план отката, потому что down‑миграции — это сложно. Если вы используете Claude Code для миграций, нужны страховки и конкретный контекст.

Когда в этой статье говорится, что изменение «безопасно», это значит три вещи:

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

Цель — чтобы миграции стали рутинной работой: предсказуемыми, тестируемыми и скучными.

Правила безопасности, которые стоит соблюдать перед формулировкой подсказки

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

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

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

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

Относитесь к миграциям как к коду для продакшна, а не как к быстрому скрипту. Даже если вы собираете приложение на платформе вроде Koder.ai (Go backend с PostgreSQL и React или Flutter клиентами), база данных — это общий ресурс. Ошибки стоят дорого.

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

  • Одно изменение на миграцию: expand, потом backfill, затем переключение кода, затем cleanup.
  • Избегайте долгих блокировок: используйте CONCURRENTLY для индексов и маленькие батчи для обновлений.
  • Требуйте план отката для каждого шага, включая способ остановки посреди бэкафилла.
  • Требуйте проверочные запросы и метрики успеха (число строк, доля NULL, тайминги).
  • Требуйте runbook: как запускать, за чем следить и кого тревожить.

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

Что включить в подсказку, чтобы Claude Code оставался в реальности

Claude может писать приличный SQL по расплывчатому запросу, но безопасные миграции требуют контекст. Относитесь к подсказке как к мини‑техническому заданию: покажите, что есть, объясните, что нельзя ломать, и определите, что значит «безопасно» для вашего rollout.

Начните с вставки только тех фактов о базе, которые действительно важны. Включите определение таблицы и релевантные индексы и ограничения (PK, UNIQUE, FK, CHECK, триггеры). Если вовлечены связанные таблицы — вставьте их фрагменты тоже. Маленький, точный отрывок не даст модели угадывать имена или пропускать важное ограничение.

Добавьте реальные масштабы. Число строк, объём таблицы, скорость записей и пиковый трафик меняют план. «200M строк и 1k записей/с» — это совсем другая миграция, чем «20k строк и в основном чтения». Также укажите версию Postgres и как у вас выполняются миграции (в одной транзакции или несколькими шагами).

Опишите, как приложение использует данные: важные чтения, записи и фоновые задания. Примеры: «API читает по email», «воркеры обновляют статус» или «отчёты сканируют по created_at». Это определяет, нужен ли expand/contract, флаги фич и насколько безопасен бэкафилл.

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

  • Текущие фрагменты схемы и цель
  • Предположения о масштабе (строки, записи/с, окно обслуживания)
  • Зависимости приложения (запросы/эндпойнты/джобы)
  • Жёсткие требования (без даунтайма, избегать долгих блокировок, не переписывать всю таблицу)
  • Результат: SQL плюс план на понятном языке, верификация и откат

Запрос и SQL + план заставляют модель думать о порядке, рисках и проверках перед релизом.

Expand/contract простыми словами (и когда использовать)

Паттерн expand/contract меняет базу данных PostgreSQL без разрыва приложения во время изменений. Вместо одного рискованного переключения вы даёте базе возможность поддерживать старую и новую форму данных в течение некоторого времени.

Думайте так: сначала добавьте новое безопасно (expand), постепенно переключайте трафик и данные, и только потом уберите старые элементы (contract). Это особенно полезно при работе с AI, потому что заставляет планировать «грязную» середину.

Четыре фазы

Практический поток выглядит так:

  • Expand: добавьте новый nullable столбец или таблицу, добавьте индекс при необходимости и вводите ограничения так, чтобы избежать блокировок (например, добавление ограничения с NOT VALID, когда это уместно).
  • Compatibility: обновите приложение так, чтобы оно работало с обеими формами. Это может быть dual‑write (писать в оба) или read‑fallback (читать новое, если есть, иначе старое).
  • Backfill: копируйте старые данные в новое место малыми батчами с чекпоинтами и возможностью возобновления.
  • Contract: когда уверены, что всё использует новый путь, ужесточьте правила (сделайте столбец NOT NULL, провалидируйте ограничения), затем удалите старые столбцы или таблицы.

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

Полезный приём — планировать два релиза. Релиз 1 делает expand и compatibility так, чтобы ничего не ломалось при неполном бэкафилле. Релиз 2 делает contract только после подтверждения, что новый код и новые данные на месте.

Шаблон безопасной подсказки для миграций expand/contract

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

You are helping me plan a PostgreSQL expand-contract migration.

Context
- App: [what the feature does, who uses it]
- Database: PostgreSQL [version if known]
- Table sizes: [rough row counts], write rate: [low/medium/high]
- Zero/near-zero downtime required: [yes/no]

Goal
- Change: [describe the schema change]
- Current schema (relevant parts):
  [paste CREATE TABLE or \\d output]
- How the app will change (expand phase and contract phase):
  - Expand: [new columns/indexes/triggers, dual-write, read preference]
  - Contract: [when/how we stop writing old fields and remove them]

Hard safety requirements
- Prefer lock-safe operations. Avoid full table rewrites on large tables when possible.
- If any step can block writes, call it out explicitly and suggest alternatives.
- Use small, reversible steps. No “big bang” changes.

Deliverables
1) UP migration SQL (expand)
   - Use clear comments.
   - If you propose indexes, tell me if they should be created CONCURRENTLY.
   - If you propose constraints, tell me whether to add them NOT VALID then VALIDATE.

2) Verification queries
   - Queries to confirm the new schema exists.
   - Queries to confirm data is being written to both old and new structures (if dual-write).
   - Queries to estimate whether the change caused bloat/slow queries/locks.

3) Rollback plan (realistic)
   - DOWN migration SQL (only if it is truly safe).
   - If down is not safe, write a rollback runbook:
     - how to stop the app change
     - how to switch reads back
     - what data might be lost or need re-backfill

4) Runbook notes
   - Exact order of operations (including app deploy steps).
   - What to monitor during the run (errors, latency, deadlocks, lock waits).
   - “Stop/continue” checkpoints.

Output format
- Separate sections titled: UP.sql, VERIFY.sql, DOWN.sql (or ROLLBACK.md), RUNBOOK.md

Две дополнительные строки, полезные на практике:

  • Попросите пометить любой шаг, блокирующий записи, как RISK: blocks writes, и указать, когда его запускать (off‑peak vs anytime).
  • Вынудите честность по поводу блокировок: "If you're not sure whether a statement takes an ACCESS EXCLUSIVE lock, say so and offer a safer option."

Частые операции схемы и как просить более безопасный SQL

Получайте более безопасные черновики SQL
Попросите Koder.ai подготовить SQL миграции, проверочные запросы и план отката.
Сгенерировать SQL

Маленькие изменения схем всё равно могут навредить, если они берут долгие блокировки, переписывают большие таблицы или падают на полпути. Когда вы используете Claude Code для миграций, просите SQL, который избегает переписей и сохраняет работоспособность приложения, пока база догоняет.

Добавление столбцов и дефолтов (без долгих блокировок)

Добавление nullable столбца обычно безопасно. Добавление столбца с NOT NULL и дефолтом может быть рискованным на старых версиях Postgres, потому что это может переписать всю таблицу.

Безопасный подход — двухшаговое изменение: добавьте столбец как NULL без дефолта, заполните батчами, затем поставьте дефолт для новых строк и сделайте NOT NULL после проверки.

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

Индексы, FK, ограничения, дропы

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

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

При ужесточении ограничений (NOT NULL, UNIQUE, CHECK) просите «сначала почистить, потом включить». Миграция должна найти плохие строки, исправить их, а затем уже включать ограничение.

Удаляйте объекты только после полного цикла релиза и подтверждения, что никто их не читает.

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

  • Укажите поведение блокировок и ожидаемое время выполнения.
  • Используйте CONCURRENTLY для больших индексов и укажите ограничения транзакций.
  • Предпочитайте NOT VALID, затем VALIDATE для новых внешних ключей.
  • Отделяйте бэкафилл от включения NOT NULL/UNIQUE.
  • Удаляйте объекты только после полного релиза и верификации.

Как просить бэкафилл, который медленный, ровный и восстанавливаемый

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

Начните с приёмных проверок, которые легко запустить и тяжело оспорить: ожидаемые числы строк, целевой уровень NULL и ряд spot‑проверок (например, сравнить старые и новые значения для 20 случайных ID).

Попросите план батчирования. Батчи держат блокировки короткими и уменьшают сюрпризы. Хороший запрос указывает:

  • Как батчить (диапазоны PK или временные окна по created_at)
  • Целевой размер батча (например, 5,000–50,000 строк)
  • Паузы между батчами на горячих таблицах
  • Каждый батч — отдельная явная транзакция (не одна большая транзакция)

Требуйте идемпотентности, потому что бэкафилл может упасть на полпути. SQL должен быть безопасен для повторного запуска без дублирования или порчи данных. Типичные паттерны: "обновлять только там, где new_col IS NULL" или детерминированное правило, где один и тот же ввод всегда даёт одинаковый вывод.

Также опишите, как приложение остаётся корректным во время бэкафилла. Если новые записи продолжают приходить, нужен мост: dual‑write в коде, временный триггер или read‑fallback (читать новое, если есть, иначе старое). Скажите, какой подход вы сможете безопасно задеплоить.

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

Пример: вы добавляете users.full_name, вычисляемый из first_name и last_name. Безопасный бэкафилл обновляет только строки, где full_name IS NULL, идёт по ID‑диапазонам, фиксирует последний обработанный ID и гарантирует корректность новых регистраций через dual‑write до полного переключения.

Как просить план отката, который работает в реальной жизни

Деплойте в правильном порядке
Деплойте приложение после шагов expand, затем постепенно бэкафилл с проверками.
Выпустить приложение

План отката — это не просто «напишите down‑миграцию». Это две задачи: отмена изменения схемы и работа с данными, которые могли измениться, пока новая версия была жива. Откат схемы часто возможен. Откат данных часто — нет, если не предусмотреть его заранее.

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

Попросите чёткие триггеры отката, чтобы в инциденте не было спора. Примеры:

  • Ошибки или рост латентности выше порога в течение 10 минут
  • Критический запрос регрессировал в плане (например, seq scan на горячей таблице)
  • Бэкафилл отстаёт более чем на N часов
  • Проверки данных провалились (NULL там, где нельзя, дубликаты, отсутствующие строки)
  • Шаг миграции блокирует записи больше X секунд

Требуйте полный пакет отката, а не только SQL: down‑миграция (только если безопасна), переключение в конфиге/коде приложения для совместимости и как остановить фоновые задания.

Обычно полезна такая подсказка:

Produce a rollback plan for this migration.
Include: down migration SQL, app config/code switches needed for compatibility, and the exact order of steps.
State what can be rolled back (schema) vs what cannot (data) and what evidence we need before deciding.
Include rollback triggers with thresholds.

Перед релизом сделайте «safety snapshot», чтобы сравнить до и после:

  • Числа строк для затронутых таблиц (и ключевых подмножеств)
  • Набор sample‑запросов с ожидаемыми результатами
  • Простые агрегаты (sum, min/max) для тронутых столбцов
  • Небольшой список ID для spot‑проверок до и после

Также будьте ясны, когда не стоит откатываться. Если вы просто добавили nullable столбец и приложение dual‑write, исправление вперёд (hotfix, пауза бэкафилла, затем возобновление) часто безопаснее, чем откат и ещё большая рассинхронизация.

Частые ошибки при AI‑помощи в миграциях

AI может быстро писать SQL, но он не видит вашу продовую базу. Большинство провалов происходит, когда подсказка расплывчата и модель «додаёт» недостающие детали.

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

Ещё одна ошибка — отправить expand, backfill и contract в одном релизе. Это убирает точку возврата. Если бэкафилл идёт долго или падает, вы останетесь с приложением, которое ожидает финального состояния.

Чаще всего встречаются:

  • Бэкафиллы без идемпотентности и отслеживания прогресса
  • Добавление NOT NULL/UNIQUE/FK до очистки и валидации данных
  • Долгие транзакции без таймаутов на запросы или блокировки
  • Отсутствие проверочных запросов, из‑за чего проблемы скрываются до поведения пользователей

Конкретный пример: "переименовать столбец и обновить приложение." Если план переименования и бэкафилла делает всё в одной транзакции, медленный бэкафилл удержит блокировки и сломает живой трафик. Безопасная подсказка вынуждает мелкие батчи, явные таймауты и проверки перед удалением старого пути.

Что проверять в staging перед релизом

Staging выявляет проблемы, которые не проявляются в маленькой dev‑базе: долгие блокировки, неожиданные NULL, отсутствующие индексы и забытые пути в коде.

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

Запустите миграцию на реалистичных данных. Идеально — недавняя копия продакшена с маской чувствительных полей. Если так нельзя, хотя бы смоделируйте объёмы и «горячие точки» (большие таблицы, широкие строки, многоиндексные таблицы). Запишите тайминги по каждому шагу, чтобы понимать ожидания в проде.

Короткий чеклист для staging:

  • Схема соответствует плану (столбцы, типы, ограничения, индексы)
  • Тайминги записаны на реалистичных объёмах
  • Совместимость проверена: старое приложение с новой схемой и новое приложение со старой схемой (если план это допускает)
  • Выполнены проверочные запросы: доля NULL, числа строк, orphan checks для новых FK, выборочные чтения
  • Отслеживались операционные сигналы во время запуска: блокировки, дедлоки, таймауты, медленные запросы

Наконец, тестируйте реальные пользовательские потоки, а не только SQL. Создавайте, обновляйте и читайте записи, затронутые изменением. Если план expand/contract, подтвердите, что обе схемы работают до финального cleanup.

Реалистичный пример: менять столбец без поломки пользователей

Получайте вознаграждение за участие
Поделитесь тем, что сделали с Koder.ai, и зарабатывайте кредиты за созданный контент.
Заработать кредиты

Предположим, у вас есть users.name, где хранят полные имена вроде "Ada Lovelace". Вы хотите first_name и last_name, но нельзя сломать регистрацию, профили или админку во время rollout.

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

ALTER TABLE users ADD COLUMN first_name text;
ALTER TABLE users ADD COLUMN last_name text;

Затем обновите поведение приложения для поддержки обеих форм. В Релизе 1 приложение должно читать из новых колонок, если они есть, иначе падать обратно на name, и писать в оба столбца, чтобы новые данные были согласованы.

Дальше идёт бэкафилл. Запустите батчевую задачу, которая обновляет небольшие куски строк за раз, фиксирует прогресс и может быть безопасно приостановлена. Например: обновлять users, где first_name IS NULL, по возрастающему ID, по 1,000 строк за раз и логировать число изменённых строк.

Перед ужесточением правил проверьте в staging:

  • Новые регистрации заполняют first_name и last_name и всё ещё пишут name
  • Существующие пользователи отображаются корректно, даже если есть только name
  • Бэкафилл можно останавливать и возобновлять без дублирования работы
  • После завершения бэкафилла не осталось неожиданных NULL
  • Основные запросы по users не стали заметно медленнее

Релиз 2 переключает чтение только на новые столбцы. Лишь после этого добавляйте ограничения (например, SET NOT NULL) и удаляйте name в отдельном последующем деплое.

Для отката — держите всё просто. Приложение продолжает читать name в процессе перехода, а бэкафилл можно остановить. Если нужно откатить Релиз 2, переключите чтения обратно на name и оставьте новые столбцы до стабилизации.

Следующие шаги: превратите подсказки в повторяемую рутину миграций

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

Стандартизируйте, что должна содержать каждая заявка на миграцию:

  • Текущая схема и точное изменение (таблицы, столбцы, индексы)
  • Ограничения и факты о трафике (размер таблиц, скорость записей, допустимый даунтайм)
  • Последовательность релиза (expand, деплой приложения, backfill, contract)
  • Как будете наблюдать прогресс (запросы/метрики, ожидаемое время)
  • Шаги отката (что откатывать первым, какие данные могут остаться потеряны)

Решите заранее, кто за что отвечает. Простое разделение ролей предотвращает ситуацию «каждый думал, что кто‑то другой это сделал»: разработчики готовят подсказку и миграционный код, ops отвечает за тайминг и мониторинг в проде, QA проверяет staging и крайние случаи, и один человек принимает финальное go/no‑go.

Если вы строите приложения через чат, полезно заранее описать последовательность, прежде чем генерировать SQL. Для команд, использующих Koder.ai, Planning Mode — естественное место для записи этой последовательности; снапшоты и откаты помогут сократить радиус поражения при неожиданностях.

После релиза запланируйте очистку (contract) сразу, пока контекст свеж — чтобы старые столбцы и временный совместимый код не оставались месяцами.

FAQ

Почему изменения схемы PostgreSQL ломают прод, даже если SQL кажется простым?

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

Типичные сценарии отказа:

  • Старый код приложения обращается к новому столбцу/ограничению и падает
  • Миграция берёт сильную блокировку на горячей таблице и запросы таймаутятся
  • «Маленькое» изменение тихо перезаписывает или удаляет данные
  • Индекс/валидация работают дольше, чем ожидалось, и вызывают медленные запросы
Какой способ по умолчанию самый безопасный для изменения схемы без даунтайма?

Используйте подход expand/contract:

  • Expand: добавьте новые nullable столбцы/таблицы/индексы безопасным образом
  • Compatibility: задеплойте код, который умеет читать/писать обе формы данных
  • Backfill: копируйте данные малыми батчами с чекпоинтами
  • Contract: ужесточите ограничения и удалите старые поля только после полного цикла релиза

Так обе версии приложения остаются работоспособными во время отката.

Какие дополнительные риски вносят AI‑сгенерированные миграции?

Модель может сгенерировать корректный SQL, который тем не менее небезопасен для вашего масштаба или процесса релиза.

Типичные риски, связанные с AI:

  • Угадывание имён таблиц/столбцов или пропуск важного ограничения
  • Предложение «big bang» миграции, которая лишает возможности отката
  • Игнорирование поведения блокировок, ограничений транзакций и долгих построений индексов
  • Словесные обещания об откате, когда данные трансформируются или удаляются

Рассматривайте AI‑выход как черновик и требуйте плана выполнения, проверок и шагов отката.

Что мне нужно вставить в подсказку, чтобы Claude Code не гадал?

Вставьте в подсказку только факты, от которых зависит миграция:

  • Релевантные CREATE TABLE фрагменты (индексы, FK, UNIQUE/CHECK, триггеры)
  • Версия Postgres и режим выполнения миграций (одна транзакция vs несколько шагов)
  • Масштаб: число строк, объём таблицы, скорость записей, пиковая нагрузка
  • Как приложение использует данные (критические чтения/записи/джобы)
  • Жёсткие ограничения (без даунтайма, избегать полной перезаписи таблицы, лимит блокировок)
  • Результат: UP SQL + проверочные запросы + план отката + runbook

Это предотвращает угадывание и заставляет модель думать о порядке операций.

Стоит ли объединять изменение схемы и бэкафилл в одной миграции?

Правило по умолчанию: разделяйте их.

Практический разрыв:

  • Миграция 1: expand схемы (новые столбцы/таблицы, возможно NOT VALID ограничения)
  • Деплой приложения: совместимый код (read‑fallback или dual‑write)
  • Бэкафилл: пакетная обработка с отслеживанием прогресса
  • Миграция 2: contract (валидировать ограничения, установить NOT NULL, удалить старые столбцы)

Сворачивание всего в один шаг лишает вас точки возврата и усложняет диагностику.

Как добавить новый столбец с дефолтом, не вызвав долгих блокировок?

Предпочтительный паттерн:

  1. ADD COLUMN ... NULL без дефолта (быстро)
  2. Бэкафилл малыми пакетами
  3. Установить дефолт для новых строк
  4. Добавить NOT NULL только после верификации

Добавление ненулевого дефолта сразу может перезаписать всю таблицу на старых версиях Postgres.

Когда использовать CREATE INDEX CONCURRENTLY и в чём подводный камень?

Просите CREATE INDEX CONCURRENTLY для больших/горячих таблиц и отметьте, что он не запускается внутри транзакции (ваше средство миграции должно это поддерживать).

Укажите ожидаемое время выполнения и метрики для мониторинга (ожидание блокировок, латентность запросов). Для проверки — сравните EXPLAIN план до/после в staging.

Как безопасно добавить внешний ключ на большой таблице?

Добавляйте FK как NOT VALID сначала, затем валидируйте:

  • Добавление FK как NOT VALID делает шаг менее затратным
  • Запустите VALIDATE CONSTRAINT отдельно, когда сможете наблюдать за процессом

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

Как запросить бэкафилл, который не разрушит прод и может быть возобновлён?

Хороший бэкафилл — это батчированный, идемпотентный и перезапускаемый.

Практические требования:

  • Батч по диапазонам PK или временным окнам
  • Обновлять только те строки, которые ещё требуют обработки (например, WHERE new_col IS NULL)
  • Держать батчи в коротких транзакциях; при необходимости делать паузы между батчами
  • Отслеживать прогресс (последний обработанный ID, число обновлённых строк, время начала)
  • Обеспечить корректность приложения во время бэкафилла (dual‑write, триггер или read‑fallback)

Это делает бэкафилл выживаемым при реальной нагрузке.

Как выглядит реалистичный план отката для изменений схемы?

Цель отката: быстро восстановить совместимость приложения, даже если данные не удастся полностью вернуть.

Рабочий план отката должен включать:

  • Можно ли безопасно выполнить DOWN SQL; если нет — подробный runbook
  • Точный порядок: остановить/приостановить бэкафилл‑джобы, задеплоить откат кода, затем шаги по схеме
  • Чёткие триггеры отката (ошибки, рост латентности, ожидания блокировок, провал проверок данных)
  • Заявление, что можно откатить (схема) и что нельзя (данные)

Часто самый безопасный откат — вернуть чтение на старое поле, оставив новые столбцы на месте.

Содержание
Что делает изменение схемы PostgreSQL рискованнымПравила безопасности, которые стоит соблюдать перед формулировкой подсказкиЧто включить в подсказку, чтобы Claude Code оставался в реальностиExpand/contract простыми словами (и когда использовать)Шаблон безопасной подсказки для миграций expand/contractЧастые операции схемы и как просить более безопасный SQLКак просить бэкафилл, который медленный, ровный и восстанавливаемыйКак просить план отката, который работает в реальной жизниЧастые ошибки при AI‑помощи в миграцияхЧто проверять в staging перед релизомРеалистичный пример: менять столбец без поломки пользователейСледующие шаги: превратите подсказки в повторяемую рутину миграцийFAQ
Поделиться