Запрос ждёт блокировку, которую держит другая сессия
still waiting for ShareLock on transaction в логе PostgreSQL: сессия дольше секунды ждёт строку, занятую другой транзакцией. Как найти того, кто держит блокировку.
Что это значит
Это сообщение пишет параметр log_lock_waits: запрос ждёт блокировку дольше deadlock_timeout (по умолчанию одна секунда). Ошибки ещё нет. Для пользователя это выглядит как «сохранение висит».
Одиночные строки с ожиданием в одну-две секунды нормальны под нагрузкой. Плохо, когда ожидания длятся минутами или идут пачкой от одного процесса.
Как проверить
Следующая строка лога называет виновника: DETAIL: Process holding the lock: 456. Wait queue: 12345. Посмотреть вживую:
select a.pid, a.state, now() - a.xact_start as xact_age, pg_blocking_pids(a.pid) as blocked_by, left(a.query, 100)
from pg_stat_activity a where a.wait_event_type = 'Lock';
Затем найти сессию из blocked_by. Состояние idle in transaction у неё означает, что приложение открыло транзакцию и не закрыло.
Что сделать
- Если блокирующая сессия простаивает в транзакции давно, завершить её:
select pg_terminate_backend(456);. - Поставить
idle_in_transaction_session_timeout, чтобы такие сессии не жили часами. - Повторяющуюся пару запросов передать разработчикам с текстами обоих.
- Проверить, не идёт ли в это время обслуживание: перестроение индексов и изменение структуры таблиц берут тяжёлые блокировки.
rxdoctor показывает такие сессии пунктом PG-04 вместе с номерами блокирующих процессов.