PostgreSQL pg_stat_statements: найти медленные запросы

Категория: Postgresql · Язык: SQL · Обновлено:

pg_stat_statements собирает статистику выполнения SQL-запросов: число вызовов, суммарное и среднее время, прочитанные строки. Запросы нормализуются, поэтому одинаковые обращения с разными литералами попадают в одну строку. Это основной инструмент для поиска запросов, которые нагружают PostgreSQL.

Включить расширение и посмотреть топ

SQL
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

SELECT
    calls,
    round(total_exec_time::numeric, 1) AS total_ms,
    round(mean_exec_time::numeric, 2) AS mean_ms,
    rows,
    query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

Одного CREATE EXTENSION недостаточно: библиотека должна быть загружена через shared_preload_libraries = 'pg_stat_statements' в postgresql.conf, после чего нужен перезапуск сервера. Без этого CREATE EXTENSION завершится ошибкой о недоступной библиотеке. В Docker-образе PostgreSQL расширение уже включено в поставку.

Столбцы total_exec_time и mean_exec_time появились в PostgreSQL 13; в более старых версиях они называются total_time и mean_time. Время указано в миллисекундах. calls показывает количество выполнений, а rows — суммарное число возвращённых или затронутых строк.

Нормализация заменяет литералы на $1, поэтому запрос с WHERE id = 42 и WHERE id = 7 считается одним. Для сравнения конкретных планов используйте EXPLAIN (ANALYZE, BUFFERS) на реальном запросе. Статистика хранится в shared memory и сбрасывается при перезапуске сервера, поэтому снимайте показатели после прогрева и не делайте выводов по одной минуте.

Сбросить статистику после релиза

SQL
SELECT pg_stat_statements_reset();

Сброс полезен после деплоя или изменения индексов, чтобы отделить новые запросы от старых. Не выполняйте его на общем сервере без предупреждения: коллеги потеряют накопленные данные. Ограничьте доступ к представлению: текст запросов может содержать имена таблиц и фрагменты условий, хотя литералы и скрыты.

Включайте track_io_timing = on, если нужны показатели чтения с диска, и track_planning = on для времени планирования. Сами по себе цифры не указывают на проблему: запрос с большим total_exec_time может быть редким, а с большим mean_exec_time — выполняться на каждом запросе приложения.

Документация: pg_stat_statements, monitoring stats.