Запрос завис: ищем блокирующую транзакцию в PostgreSQL
Находим блокирующие сеансы PostgreSQL, ограничиваем ожидание и ищем причину долгой транзакции.
- Ожидающий запросНаходим сеанс и тип ожидания
- Блокирующая транзакцияПроверяем владельца блокировки и её длительность
- Ограничение ожиданияВыбираем тайм-аут, разбираемся с транзакцией
Пользователь нажал «Сохранить», загрузка сервера невелика, а ответа всё нет. Возможно, запрос ничего тяжёлого не вычисляет — он ждёт блокировку другой транзакции. Выясним, кто кого блокирует, чем занят этот сеанс и как ограничить ожидание, не завершая процессы наугад.
Находим ожидающие сеансы
SELECT pid, state, wait_event_type, wait_event,
pg_blocking_pids(pid) AS blockers,
now() - xact_start AS transaction_age
FROM pg_stat_activity
WHERE datname = current_database()
AND wait_event_type = 'Lock';Для просмотра сведений о чужих сеансах потребуются подходящие права. Полученные PID — отправная точка расследования, а не список процессов для немедленного завершения. Сравните их с приложением, журналом запросов и временем начала транзакции.
Ограничиваем ожидание локально
BEGIN;
SET LOCAL lock_timeout = '2s';
SET LOCAL statement_timeout = '10s';
UPDATE accounts SET touched_at = now() WHERE id = 42;
COMMIT;В примере используется таблица accounts с нужными столбцами. lock_timeout ограничивает ожидание блокировки, а statement_timeout — длительность выполнения команды. Выбирайте значения под конкретную операцию, а не переносите эти числа во все запросы. После ошибки транзакцию нужно корректно откатить; приложение должно обработать отказ.
Сокращаем время удержания блокировки
Частый источник проблемы — транзакция, оставленная открытой во время сетевого запроса, пользовательского диалога или долгой обработки файла. Сократите участок между BEGIN и завершением. Если несколько операций берут одни и те же ресурсы, используйте согласованный порядок доступа.
Не завершайте сеанс только потому, что он самый старый. Узнайте, какую работу он выполняет и кто за неё отвечает: откат тоже может быть дорогим. После разбора стоит сократить транзакцию или изменить порядок работы и время ожидания. Иначе та же блокировка появится снова.
