Один медленный запрос в журнале не обязательно создаёт основную нагрузку. Частый короткий запрос может суммарно потреблять больше времени. pg_stat_statements позволяет сравнить нормализованные SQL по числу вызовов, общему и среднему времени.
Сначала проверить доступность
SELECT version();
SHOW shared_preload_libraries;
SHOW compute_query_id;
SELECT name, installed_version
FROM pg_available_extensions
WHERE name = 'pg_stat_statements';Пакет расширения должен присутствовать на сервере. Для управляемого сервиса используйте поддерживаемый провайдером способ включения. Не заменяйте существующее значение shared_preload_libraries одной строкой: в нём уже могут быть нужные модули.
pg_stat_statements добавляется в список preload-библиотек, что требует перезапуска PostgreSQL, а не только reload. Расчёт query ID должен быть включён; штатные auto или on подходят для этого модуля. После согласованного изменения и перезапуска в нужной базе создаётся представление расширения:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;Команда требует соответствующих полномочий. Не выдавайте прикладному пользователю superuser ради чтения отчёта. Тексты запросов других пользователей доступны при подходящих правах, например pg_read_all_stats, но такое право тоже нужно выдавать осознанно.
Начать с общего времени
SELECT queryid,
calls,
round(total_exec_time::numeric, 1) AS total_ms,
round(mean_exec_time::numeric, 2) AS mean_ms,
rows,
left(query, 180) AS query_sample
FROM pg_stat_statements
WHERE dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
ORDER BY total_exec_time DESC
LIMIT 20;Колонки примера относятся к современным версиям PostgreSQL. Для старой версии сначала проверьте структуру view и справку именно своего major release. Общий список не является перечнем текущих активных запросов: это накопленная статистика.
Разделить частоту и цену вызова
Сортировка total_exec_time находит суммарно дорогие структуры запросов. Большое mean_exec_time у редкого вызова может быть важным для задержки отдельной операции, но не для общей загрузки. Изучайте обе величины вместе с calls, количеством строк и контекстом приложения.
Агрегированные значения не дают p95/p99 автоматически. Для хвостовых задержек сопоставьте их с метриками приложения и выборочными планами исполнения. Один нормализованный SQL может работать по разным параметрам и набору данных.
Оценивать интервал, а не всю историю
Сохраните снимок счётчиков до и после интересующего периода. Сравнивайте приращения по составному идентификатору базы, пользователя и queryid. Учитывайте перезапуск, reset и вытеснение записей из статистики. Не запускайте pg_stat_statements_reset только ради удобства своего отчёта: это нарушит чужое наблюдение.
Стабильность queryid между major-версиями не гарантируется, поэтому сравнение до и после большого обновления требует отдельной проверки.
Перейти от рейтинга к плану
Выберите запрос, воспроизведите условия на стенде и получите EXPLAIN. EXPLAIN ANALYZE действительно исполняет SQL: для изменения данных или дорогой операции это уже вмешательство, а не безусловно безопасное чтение.
Справка: Using EXPLAIN. Проверьте выборку, индексы, оценки количества строк, сортировки и временные файлы. После изменения сравните эквивалентные временные окна и нагрузку, а не только один удачный запуск.
Что сохранить в отчёте
- Версию PostgreSQL и интервал наблюдения.
- Число вызовов и приращение времени.
- Выбранную структуру SQL без лишних чувствительных значений.
- План, проверяемую гипотезу и изменение.
- Сравнение до/после при сопоставимой нагрузке.
Это помогает оптимизировать измеренную проблему, а не добавлять индексы по одному названию медленного endpoint.

Источник материала: PostgreSQL pg_stat_statements: как найти запросы, которые тратят ресурсы (англоязычный материал разработчиков). Русскоязычная инструкция подготовлена самостоятельно; технические сведения проверены 11 октября 2026 года.