Первое чтение плана PostgreSQL
Оценки, фактические строки и почему Seq Scan не всегда проблема.
Медленный запрос не обязательно лечится новым индексом. Сначала полезно понять, как PostgreSQL планирует получить результат и насколько его ожидания совпадают с реальными данными.
Начать с плана без выполнения
Предположим, в приложении есть таблица events с полями id и created_at. Это иллюстрация: используйте схему своего проекта.
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 означает ожидаемое число строк на выходе узла.
Сравнить с фактическим выполнением
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 сам по себе не ошибка: последовательное чтение может быть разумным для небольшой таблицы или большого процента строк. Индекс тоже требует чтений и обслуживания.
Проверять на похожих данных
Сохраняйте исходный план и меняйте по одному фактору. Сравнение пустой локальной базы с рабочей мало что говорит о производительности. Повторное выполнение может ускориться из-за кеша, поэтому фиксируйте условия измерения вместе с результатом.