Разбор плана запроса PostgreSQL на живой таблице журналов

Пошаговый подход к чтению EXPLAIN ANALYZE на больших таблицах логов и подбору индексов без угадывания.

Editorial Team 08.04.2026 1 минута
План выполнения PostgreSQL
Разбор тяжелого запроса на таблице журналов.

Когда таблица логов вырастает до сотен миллионов строк, привычное ощущение от EXPLAIN ANALYZE меняется: уже недостаточно увидеть Seq Scan и просто добавить индекс. Важно понять, как меняется стратегия планировщика под реальными фильтрами, сортировкой и ограничением по времени.

С чего начинать

Первый шаг — зафиксировать реальный запрос приложения, а не его упрощенную версию. Часто именно лишняя сортировка или неявное приведение типов становятся причиной потери индекса.

explain analyze
select created_at, level, message
from app_logs
where created_at >= now() - interval '1 day'
  and service_name = 'integration-api'
  and level in ('warning', 'error')
order by created_at desc
limit 200;

На что смотреть в плане

Если в узле сортировки обрабатываются сотни тысяч строк ради двухсот результатов, лучше перейти на составной индекс (service_name, created_at desc) и добиться Index Scan с ранним ограничением набора.

create index concurrently idx_app_logs_service_created_at
on app_logs (service_name, created_at desc)
include (level, message);

Дополнительный плюс дает секционирование по дате, если аналитика почти всегда ограничена коротким окном времени. Тогда планировщик даже не рассматривает старые секции.

Полезная привычка

Сохраняйте текст плана до и после изменения индексов. Это позволяет сравнивать не только итоговую скорость, но и изменение стоимости узлов, чтения буферов и объема сортировки.

План запроса PostgreSQL