Короткий ответ
EXPLAIN ANALYZE реально выполняет запрос и показывает дерево операций с оценённой и фактической стоимостью/временем/числом строк для каждого узла; Seq Scan читает всю таблицу страницами подряд, а Index Scan использует индекс, чтобы обратиться только к нужным строкам.
Как это работает подробнее
План строится снизу вверх — листовые узлы (сканы) передают строки родительским узлам (Join, Sort, Aggregate); планировщик выбирает стратегию на основе статистики (ANALYZE таблицы). Расхождение между estimated и actual rows часто сигнализирует об устаревшей статистике.
Пример кода
example.sql
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 42;
-- Seq Scan on orders (cost=0.00..2500.00 rows=50000 width=64) (actual time=0.015..35.201 rows=12 loops=1)
-- Filter: (user_id = 42)
-- Rows Removed by Filter: 49988
-- Вывод: нужен индекс на user_id, так как фильтр отбрасывает почти все строки при полном сканированииЧто использовать на практике
- Практика. При анализе медленного запроса смотрят на узлы с наибольшим actual time и на то, совпадает ли план с ожиданием; BUFFERS в EXPLAIN (ANALYZE, BUFFERS) дополнительно показывает хиты/промахи кэша страниц.
Подводные камни
- Ошибка. Смотрят только на EXPLAIN без ANALYZE и путают оценочную стоимость с реальным временем; не замечают, что планировщик иногда осознанно выбирает Seq Scan вместо Index Scan для низкой избирательности условия.