Запрос ждёт блокировку: находим владельца через pg_blocking_pids
UPDATE занимает секунды, но в плане нет тяжёлого чтения. Повтор на той же базе иногда проходит мгновенно. В такой ситуации полезно проверить ожидание блокировки, прежде чем переписывать SQL или создавать новый индекс.
Время команды включает ожидание других транзакций. pg_stat_activity показывает состояние соединения и событие ожидания, а pg_blocking_pids возвращает процессы, которые мешают ему получить блокировку. Вместе они позволяют перейти от симптома к конкретному владельцу.
Как изменить решение
SELECT waiting.pid AS waiting_pid,
waiting.wait_event_type, waiting.wait_event,
blocker.pid AS blocker_pid,
blocker.state, blocker.xact_start,
blocker.query AS blocker_query
FROM pg_stat_activity AS waiting
CROSS JOIN LATERAL unnest(pg_blocking_pids(waiting.pid)) AS b(pid)
JOIN pg_stat_activity AS blocker ON blocker.pid = b.pid;В результате будет пара ожидающее соединение–блокирующее соединение. Один запрос может иметь несколько блокирующих процессов. Если blocker.state равно idle in transaction, клиент сейчас не выполняет команду, но его незавершённая транзакция продолжает держать ресурсы.
Начните с причины незавершённой транзакции: забытый COMMIT, исключение без rollback, внешний вызов внутри блока. Убийство соединения может убрать симптом, но без исправления жизненного цикла проблема вернётся. Кроме того, остановка активной операции влияет на её пользователя.
Что проверить на своих данных
Для воспроизведения обновите строку в A и оставьте транзакцию открытой. Запустите UPDATE той же строки в B и выполните диагностический SELECT в C. После ROLLBACK A убедитесь, что B продолжил работу. Это отличает блокировку строки от нехватки соединений или медленного диска.
Доступ к текстам чужих запросов зависит от прав роли. Диагностический запрос стоит выполнять предусмотренной для наблюдения ролью, а не раздавать приложению административные полномочия. В регулярном мониторинге полезны возраст транзакции и длительность ожидания, чтобы команда узнавала о забытом блоке до того, как очередь запросов заполнит пул.
Практика дальше
Если блокировку породила незавершённая сессия приложения, исправление нужно закрепить тестом обработчика. В курсе FastAPI вы работаете с SQLAlchemy, зависимостями и pytest на последовательном backend-проекте. Это маршрут от отдельного запроса к проверяемому API; практика использует SQLite.
Посмотреть программу и практику курса
Источник: Запрос ждёт блокировку — официальная документация.
Другие задачи по теме: PostgreSQL: запись, блокировки и планы запросов.
Продолжить на практике
- FastAPI для начинающих: API с базой данных и тестами ↗
Соберёте свой первый полноценный backend на FastAPI: с базой данных, регистрацией, JWT-авторизацией и автотестами. 34 коротких урока и 140 заданий с проверкой — бесплатно.
