Разбирать log_min_duration_statement через pgBadger — рабочий, но окольный путь узнать, какие запросы реально тормозят продакшен. pg_stat_statements считает эту статистику сам, в реальном времени, без парсинга логов.

Расширение штатное (идёт в поставке PostgreSQL), но требует загрузки на уровне сервера — просто CREATE EXTENSION недостаточно:

# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'

Это параметр из тех, что применяются только при перезапуске postmaster, не reload. После рестарта:

CREATE EXTENSION pg_stat_statements;

Топ самых тяжёлых по суммарному времени запросов:

SELECT query, calls, total_exec_time, mean_exec_time, rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

Важно: колонки называются total_exec_time/mean_exec_time начиная с PostgreSQL 13 — до этого были просто total_time/mean_time (в 13-й версии время выполнения отделили от времени планирования, добавив total_plan_time). На более старой версии сервера имена колонок будут другими — стоит свериться перед тем как копировать запрос один в один.

Запросы в таблице нормализованы — конкретные значения параметров заменяются на $1, $2 и так далее, поэтому один и тот же запрос с разными WHERE id = 123 и WHERE id = 456 попадает в одну строку статистики, а не размножается на тысячи почти одинаковых записей.

Сбросить накопленную статистику (например, перед нагрузочным тестом, чтобы не путать старые результаты с новыми):

SELECT pg_stat_statements_reset();

Частая забытая деталь — pg_stat_statements.max ограничивает количество отслеживаемых уникальных запросов (по умолчанию 5000); на инстансе с сильно динамическим SQL (много ad-hoc запросов без параметризации) старые записи начинают вытесняться раньше, чем успеваешь их посмотреть.

#postgresql #dba