#Симптом и границы применимости
При зависшем запросе PostgreSQL представление pg_stat_activity позволяет найти сеанс, ожидающий блокировку, и блокирующие backend через pg_blocking_pids(). Это диагностика, а не разрешение на безусловное завершение чужих транзакций.
#Как отличить возможные причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Долгая открытая транзакцияСеанс idle in transaction удерживает блокировки после незавершённого UPDATE. | Долгое xact_start и ожидающие запросы | Найти владельца операции |
| DDL против DMLИзменение таблицы ожидает другие транзакции. | wait_event_type=Lock | Согласовать окно миграции |
| Недостаточная видимостьУчётная запись не видит полные запросы других ролей. | NULL в поле query | Запросить pg_read_all_stats |
#Пошаговая диагностика и безопасное исправление
- 1. Подключитесь к правильному экземпляруОткройте psql с учётной записью для мониторинга и выберите рабочую базу. Убедитесь через current_database(), что исследуете нужный экземпляр; запрос статистики сам данные не меняет.
- 2. Получите список ожидающих сеансовВыполните выборку с pid, state, wait_event_type и возрастом транзакции. Не предполагайте, что каждый state=active выполняет полезную работу: он может ожидать блокировку.
- psql; чтениеSQLКомандаpsql; чтение. Текст запросов может содержать чувствительные значения — не публикуйте вывод.
SELECT pid, usename, state, wait_event_type, wait_event, now()-xact_start AS xact_age, left(query,160) AS query FROM pg_stat_activity WHERE datname=current_database() AND pid<>pg_backend_pid() ORDER BY xact_start NULLS LAST LIMIT 40;
- 3. Найдите конкретный блокирующий процессВызовите pg_blocking_pids для ожидающих сеансов; именно он учитывает внутренние правила блокировок. Связь с PID и время помогут найти приложение-владельца.
- psql, чтениеSQLКомандаpsql, чтение. Пустой массив означает отсутствие блокирующих PID в момент проверки.
SELECT pid, pg_blocking_pids(pid) AS blockers, wait_event_type, state FROM pg_stat_activity WHERE datname=current_database() AND wait_event_type='Lock';
- 4. Проверьте источник долгой транзакцииНайдите сервер приложения и журнал операции по application_name, client_addr, времени и PID. Если видите idle in transaction, это повод проверить забытый COMMIT/ROLLBACK, а не сразу разрывать соединение.
- 5. Оцените последствия отмены командыpg_cancel_backend(pid) отменяет текущий запрос, pg_terminate_backend(pid) разрывает весь сеанс и откатывает незавершённую транзакцию; обе операции способны повредить текущий бизнес-процесс. Не запускайте их только по цифре PID.
- 6. Устраните причину на тестеВ коде приложения сократите транзакцию, уберите ожидание пользователя внутри BEGIN/COMMIT и добавьте разумный lock_timeout для особо чувствительных миграций. Проверьте, что явный ROLLBACK выполняется при ошибке.
- 7. Повторите проверку блокировокПосле согласованного исправления дважды снимите pg_stat_activity в момент нагрузки; отсутствие долговременных ожидающих сеансов важнее однократного исчезновения конкретного PID.
- 8. Зафиксируйте наблюдение в мониторингеСохраняйте число сеансов, ожидающих Lock, и максимальный возраст транзакции без полного SQL с персональными данными. Настройте оповещение при продолжительном idle in transaction.
#Как проверить, что проблема устранена
В тестовом сценарии ожидающие команды завершаются, pg_blocking_pids не показывает постоянного блокирующего PID, запросы не застревают повторно.
#Если исправление не помогло
Если блокировки возвращаются, сравните их по application_name и порядку операций. При отсутствии доступа к статистике попросите роль pg_read_all_stats, а не статус суперпользователя для приложения.