Справочник системных ошибок и решений

Windows Server, Active Directory, 1С:Предприятие, СУБД, Linux, Cisco, MikroTik, Asterisk.

⚠️ Важная информация Все материалы, инструкции, команды и скрипты на сайте предоставлены исключительно в ознакомительных целях. Их применение может повлиять на работу операционной системы, программного обеспечения, баз данных, сетевого оборудования и других компонентов инфраструктуры. Перед выполнением действий создайте резервную копию и по возможности протестируйте изменения в безопасной среде. Пользователь самостоятельно оценивает риски и несет ответственность за результат. При отсутствии необходимых знаний обратитесь к квалифицированному ИТ-специалисту.

PG_LOCK_TIMEOUT_DEADLOCK Linux / DevOps

Траблшутинг блокировок в PostgreSQL: поиск ExclusiveLock и дерево зависимостей

Обновлено: 24.08.2026
  • Резкое накопление сотен активных соединений со статусом ожидания WaitEventType: Lock.
  • Ошибки в приложениях: ERROR: deadlock detected или canceling statement due to lock timeout.
  • DDL-миграции (ALTER TABLE, CREATE INDEX) блокируют обычные SELECT/UPDATE операции.

1. Запрос для выявления блокировщиков и ожидающих сессий

SELECT 
    blocked_locks.pid     AS blocked_pid,
    blocked_activity.usename  AS blocked_user,
    blocking_locks.pid    AS blocking_pid,
    blocking_activity.usename AS blocking_user,
    blocked_activity.query    AS blocked_statement,
    blocking_activity.query   AS blocking_statement,
    now() - blocked_activity.query_start AS blocked_duration
FROM  pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks 
    ON blocking_locks.locktype = blocked_locks.locktype
    AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
    AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
    AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
    AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
    AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
    AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
    AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
    AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
    AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
    AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

2. Принудительное завершение блокирующего процесса

-- Мягкая отмена выполняемого запроса
SELECT pg_cancel_backend(blocking_pid);

-- Жесткий разрыв соединения процесса
SELECT pg_terminate_backend(blocking_pid);

3. Превентивная настройка таймаутов в postgresql.conf

# Максимальное время ожидания захвата блокировки (например, 5 секунд)
lock_timeout = 5s

# Максимальное время выполнения запроса
statement_timeout = 30s

# Авторазрыв транзакций, зависших в состоянии «idle in transaction»
idle_in_transaction_session_timeout = 10s

# Задержка перед проверкой взаимной блокировки (дедлока)
deadlock_timeout = 1s
SELECT pg_reload_conf();
💡 Практика специалистов: Всегда выполняйте добавление индексов с директивой CONCURRENTLY (CREATE INDEX CONCURRENTLY), чтобы предотвратить взятие ShareLock, блокирующего вставки (INSERT) и обновления (UPDATE).

Частые вопросы (FAQ)

В чем разница между pg_cancel_backend и pg_terminate_backend?

pg_cancel_backend отправляет сигнал SIGINT, отменяя только текущий выполняемый SQL-запрос с сохранением соединения. pg_terminate_backend отправляет SIGTERM, полностью разрывая клиентскую сессию с откатом всей транзакции.

Почему простой SELECT может стоять в очереди блокировок?

Если перед SELECT в очередь встала DDL-операция (например, ALTER TABLE, требующая AccessExclusiveLock), она блокирует все последующие запросы к таблице, даже неконфликтующие между собой.

Полезные материалы
Рекомендуем