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. Это показывает опыт работы с реальными системами.