Первое чтение плана PostgreSQL

Оценки, фактические строки и почему Seq Scan не всегда проблема.

Медленный запрос не обязательно лечится новым индексом. Сначала полезно понять, как PostgreSQL планирует получить результат и насколько его ожидания совпадают с реальными данными.

Начать с плана без выполнения

Предположим, в приложении есть таблица events с полями id и created_at. Это иллюстрация: используйте схему своего проекта.

sql
EXPLAIN
SELECT id, created_at
FROM events
WHERE created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'
ORDER BY created_at DESC
LIMIT 20;

Обычный EXPLAIN показывает план и оценки. Значения cost — внутренние условные единицы, а не миллисекунды. rows означает ожидаемое число строк на выходе узла.

Сравнить с фактическим выполнением

sql
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, created_at
FROM events
WHERE created_at >= TIMESTAMPTZ '2026-09-01 00:00:00+00'
ORDER BY created_at DESC
LIMIT 20;

ANALYZE действительно выполняет запрос. Даже SELECT может создать нагрузку; функцию с побочными эффектами он тоже выполнит. Для изменяющих запросов особенно важно сначала выбрать безопасную среду.

Что искать первым

Сравните оценку rows с actual rows, учитывая loops. Большое расхождение — повод проверить статистику и распределение данных. Посмотрите, какой узел обрабатывает много строк, прежде чем верхний LIMIT оставит двадцать.

Seq Scan сам по себе не ошибка: последовательное чтение может быть разумным для небольшой таблицы или большого процента строк. Индекс тоже требует чтений и обслуживания.

Проверять на похожих данных

Сохраняйте исходный план и меняйте по одному фактору. Сравнение пустой локальной базы с рабочей мало что говорит о производительности. Повторное выполнение может ускориться из-за кеша, поэтому фиксируйте условия измерения вместе с результатом.

Документация

PostgreSQL: Using EXPLAIN ↗