# Тяжёлые блокировки отношений _Блокировки · PostgreSQL Knowledge Base_ **TL;DR:** Каждая команда берёт на таблицу блокировку одного из 8 режимов: от ACCESS SHARE (обычный SELECT) до ACCESS EXCLUSIVE (DROP/ALTER), который конфликтует со всеми. Блокировка держится до конца транзакции. Тяжёлая блокировка отношения упорядочивает доступ к таблице как к объекту: пока кто-то её читает, нельзя посреди этого выполнить `DROP TABLE` или переписать формат через `ALTER TABLE`. Режим блокировки выбирает не пользователь, а сам PostgreSQL - минимально достаточный под команду. ## Восемь режимов | Режим | Кто берёт | |---|---| | ACCESS SHARE | `SELECT` | | ROW SHARE | `SELECT ... FOR UPDATE/SHARE` | | ROW EXCLUSIVE | `INSERT`, `UPDATE`, `DELETE` | | SHARE UPDATE EXCLUSIVE | `VACUUM`, `ANALYZE`, `CREATE INDEX CONCURRENTLY` | | SHARE | `CREATE INDEX` | | SHARE ROW EXCLUSIVE | `CREATE TRIGGER`, часть `ALTER TABLE` | | EXCLUSIVE | `REFRESH MATERIALIZED VIEW CONCURRENTLY` | | ACCESS EXCLUSIVE | `DROP`, `TRUNCATE`, `VACUUM FULL`, большинство `ALTER TABLE` | ## Правило конфликтов Вместо матрицы 8×8 запомни: всё без слова EXCLUSIVE между собой совместимо. SELECT (ACCESS SHARE) и UPDATE (ROW EXCLUSIVE) уживаются. Режимы с EXCLUSIVE конфликтуют с записью и друг с другом, а ACCESS EXCLUSIVE - вообще со всеми, включая обычный SELECT. ## До конца транзакции Тяжёлая блокировка снимается на `COMMIT`/`ROLLBACK`, а не на конце запроса. Поэтому открытый `BEGIN` с давно отработавшим `SELECT` всё ещё держит ACCESS SHARE - и это корень каскадов (см. [idle-in-transaction-cascade](/courses/postgres/kb/idle-in-transaction-cascade.md)). ## Где смотреть ```sql SELECT locktype, relation::regclass, mode, granted, pid FROM pg_locks WHERE relation = 'flights'::regclass; ``` Строка с `granted = f` значит, что кто-то ждёт в очереди. Очередь честная (FIFO), поэтому ждущий с тяжёлым режимом останавливает за собой даже совместимые запросы. Блокировки строк сюда не попадают - они в [row-locks](/courses/postgres/kb/row-locks.md). ## Команды ```sql SELECT mode, granted, pid FROM pg_locks WHERE relation = 'flights'::regclass; ``` Кто держит и кто ждёт блокировку на таблице flights ```sql LOCK TABLE flights IN ACCESS EXCLUSIVE MODE; ``` Явно взять самый тяжёлый режим (внутри транзакции) ```sql SET lock_timeout = '2s'; ``` Не ждать блокировку дольше 2 секунд - страховка для DDL на проде ## См. также - [Блокировки строк](/courses/postgres/kb/row-locks.md) - [idle-in-transaction и каскад блокировок](/courses/postgres/kb/idle-in-transaction-cascade.md) - [Взаимоблокировки (deadlock)](/courses/postgres/kb/deadlocks.md)