Какой SQL-запрос блокирует всю таблицу в PostgreSQL
Что проверяют
Понимаете ли вы, что блокировки таблицы в PostgreSQL бывают разной силы, и какие обычные команды, особенно из миграций, берут самую тяжёлую. Следом почти всегда спрашивают, почему безобидный ALTER TABLE на проде вдруг повесил все SELECT и как это предотвратить.
Как отвечать
Прямой ответ: LOCK TABLE orders;. Без указания режима он берёт ACCESS EXCLUSIVE, который конфликтует со всеми режимами, включая ACCESS SHARE от обычного SELECT. Работает только внутри транзакции и держится до COMMIT или ROLLBACK.
На практике таблицу чаще блокирует не явный LOCK, а DDL:
ACCESS EXCLUSIVE: большинство формALTER TABLE,DROP TABLE,TRUNCATE,VACUUM FULL,CLUSTER. Не проходят ни чтение, ни запись;SHARE:CREATE INDEXбезCONCURRENTLY. Чтение идёт, запись ждёт до конца построения индекса;ROW EXCLUSIVE: обычныеINSERT,UPDATE,DELETE. ДажеUPDATEбезWHEREблокирует строки, а не таблицу, и читатели его не ждут благодаря MVCC.
Главное, что стоит сказать: очередь блокировок. ALTER TABLE ждёт завершения чужой долгой транзакции, а все новые SELECT встают в очередь уже за ним. Поэтому миграции запускают с SET lock_timeout = '3s' и повтором. Со стороны Go добавьте: транзакция в pgx или database/sql без defer tx.Rollback(ctx) и без таймаута в context держит блокировки, пока жива. Кто кого держит, видно в pg_stat_activity и через pg_blocking_pids(pid).
Где спотыкаются
Думают, что UPDATE без WHERE закрывает таблицу на чтение. Он мешает другим писателям, но не читателям.
Не знают, что CREATE INDEX без CONCURRENTLY останавливает запись на всё время построения. На большой таблице это минуты простоя.
Считают короткий ALTER TABLE ADD COLUMN безопасным и не ставят lock_timeout. Сама операция мгновенная, но ожидание блокировки за чужой транзакцией кладёт сервис.