TGViewer
Всё о разработке | Леонид Ченский Всё о разработке | Леонид Ченский @leoscode · 731 subscribers
Post #156 914
Отличная дискуссия получилась — и да, большинство гуру Postgres ответило верно! Давайте спокойно разберёмся, почему.

«Совсем плохой» способпросто сделать колонку NOT NULL:
ALTER TABLE some_big_table
ALTER COLUMN foo_field SET NOT NULL;


Почему так делать очень плохо на большой таблице?

Чтобы убедиться, что в столбце нет NULL, Postgres сканирует всю таблицу. Такие изменения вокруг ADD CONSTRAINT/SET NOT NULL обычно требуют ACCESS EXCLUSIVE — самый сильный DDL-лок, конфликтующий со всеми операциями, включая чтения. Это легко превращается в stop the world на таблице, если операция длится долго.

Правильный подход: через NOT VALIDVALIDATE

Идея — разделить «включить проверку для новых записей» и «проверить историю» на два шага.

1. Добавляем ограничение без проверки истории (не блокирует обновления надолго):
ALTER TABLE some_big_table
ADD CONSTRAINT some_big_table_foo_field_not_null
CHECK (foo_field IS NOT NULL) NOT VALID;


С флагом NOT VALID добавление не сканирует таблицу и может быстро зафиксироваться. Новые/изменённые строки уже обязаны удовлетворять условию.

2. Отдельно валидируем историю:
ALTER TABLE some_big_table
VALIDATE CONSTRAINT some_big_table_foo_field_not_null;


VALIDATE CONSTRAINT сканирует только существующие строки и берёт уже SHARE UPDATE EXCLUSIVE (гораздо мягче), так что записи не блокируются так сурово, как при прямом SET NOT NULL.

Что именно могло заблокировать таблицу в нашем кейсе?

Наша SQL миграция выглядит так (все в одной транзакции):
BEGIN;

ALTER TABLE ... ADD CONSTRAINT ... CHECK (...) NOT VALID;
ALTER TABLE ... VALIDATE CONSTRAINT ...;

COMMIT;


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

Однако, когда мы используем сторонние решения для миграций (напрмер goose), мы получаем неявное повдение — миграции в одном файле будут также исполняться в рамках одной транзакции (если не укажем обратное).

В таком случае:
- Мы берем блокировку ACCESS EXCLUSIVE для добавления CONSTRAINT
- Далее эта блокировка будет удерживаться до конца работы транзакции
- Валидация нагрузки происходит долго, что приводит к тому, что транзакция превращается в долгоживующую => таблица заблокирована надолго.

Практический вывод: Делайте ADD CONSTRAINT ... NOT VALID и фиксируйте сразу (быстрый COMMIT). А VALIDATE CONSTRAINT запускайте отдельной миграции и, желательно, в спокойный период.

А чтобы не переживать насчет ваших миграций, вы можете настроить линтер: squawkhq
  • 🔥 12
  • ❤ 11
  • ⚡ 4
  • 👍 3
  • 🙏 1
More from @leoscode
  1. Sep 15, 2026Помню как в детстве хотел такого же ассистента как Jarvis у Железного человека. Сейчас буд…
  2. Aug 24, 2026Гипотетическая история Представьте завтра все датацентры «вдруг» перестанут работать. Прив…
  3. Aug 4, 2026"Капризный день"
  4. Jul 17, 2026Пользуюсь случаем, напишу тут: ищу заряжененного Go разработчика к себе в команду. Ссылка…
  5. Jul 14, 2026Утро вторника началось не с кофе… Кто положил, признавайтесь!)
  6. Jul 1, 2026Согласны? 👍 Да 🗿Нет
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →