Gymterview
middle

Какие виды блокировок существуют в PostgreSQL?

PostgreSQL использует многоуровневую систему блокировок: строковые (row-level) и табличные (table-level). Строковые блокировки не используют память менеджера блокировок — информация хранится в самих строках через xmax.

Строковые блокировки (row-level locks)

Пример
-- Явная блокировка строк
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;          -- эксклюзивная блокировка
SELECT * FROM accounts WHERE id = 1 FOR NO KEY UPDATE;   -- без блокировки FK
SELECT * FROM accounts WHERE id = 1 FOR SHARE;           -- разделяемая (для чтения)
SELECT * FROM accounts WHERE id = 1 FOR KEY SHARE;       -- мягкая разделяемая

Полезные модификаторы:

Пример
-- SKIP LOCKED — пропустить заблокированные строки (очередь задач)
SELECT * FROM task_queue
WHERE status = 'new'
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED;

-- NOWAIT — не ждать, сразу ошибка
SELECT * FROM accounts WHERE id = 1 FOR UPDATE NOWAIT;

Табличные блокировки (table-level locks)

Режим Конфликтует с
ACCESS SHARE ACCESS EXCLUSIVE
ROW SHARE EXCLUSIVE, ACCESS EXCLUSIVE
ROW EXCLUSIVE SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE
SHARE ROW EXCLUSIVE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE
ACCESS EXCLUSIVE Все режимы

Обычные операции автоматически берут блокировки: SELECT -> ACCESS SHARE, INSERT/UPDATE/DELETE -> ROW EXCLUSIVE, CREATE INDEX -> SHARE, ALTER TABLE / DROP TABLE -> ACCESS EXCLUSIVE.

Пример
-- CREATE INDEX CONCURRENTLY не блокирует запись
CREATE INDEX CONCURRENTLY idx_tx_amount ON transactions (amount);
Мониторинг блокировок
-- Посмотреть текущие блокировки
SELECT pid, relation::regclass, mode, granted
FROM pg_locks
WHERE NOT granted;

-- Найти блокирующие и ожидающие запросы
SELECT blocked.pid AS blocked_pid,
       blocked.query AS blocked_query,
       blocking.pid AS blocking_pid,
       blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_locks bl ON bl.pid = blocked.pid AND NOT bl.granted
JOIN pg_locks bk ON bk.relation = bl.relation AND bk.granted
JOIN pg_stat_activity blocking ON blocking.pid = bk.pid
WHERE blocked.pid != blocking.pid;

На собеседовании: ключевые практические знания — FOR UPDATE SKIP LOCKED для реализации очереди задач и CREATE INDEX CONCURRENTLY для создания индексов без блокировки записи на production. Это показывает опыт работы с реальными системами.