TATECHATLAS
◎ Русский
Базы данных и данные

Как читать EXPLAIN в PostgreSQL перед добавлением индекса

Найти дорогой этап и отличить оценку планировщика от измерения.

В этом материале

EXPLAIN показывает предполагаемую стратегию выполнения. EXPLAIN ANALYZE действительно выполняет запрос и даёт измерения. Сначала сравните оценки строк, фактические строки и число повторов узлов.

Начать с оценок

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

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

Измерить в подходящей среде

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

EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE customer_id = 42;

Сначала прочитайте одну строку плана

Ниже условный фрагмент, а не результат измерения реальной базы. cost=0.43..8.61 показывает оценочную стоимость старта и завершения в единицах планировщика. rows=10 — ожидаемое число строк на выходе, width=16 — оценочный средний размер выходной строки в байтах.

Часть с измерениями показывала бы 10 000 строк вместо ожидаемых 10 при одном выполнении. actual time=0.05..12.00 означает время до первой строки и до завершения в миллисекундах для этого выполнения. Большое расхождение количества строк — повод разобраться в оценке, прежде чем считать ещё один индекс готовым решением.

Index Scan using orders_customer_idx on orders
  (cost=0.43..8.61 rows=10 width=16)
  (actual time=0.05..12.00 rows=10000 loops=1)

Идите от нижних узлов и следите за повторами

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

Для обычного узла actual rows и время указаны в среднем на выполнение. При actual rows=5 и loops=1000 суммарно получается примерно 5 000 строк. Время узла может включать дочерние операции, поэтому сумма времени всех строк плана учитывает часть работы повторно. Параллельные планы требуют дополнительного разбора; общий ориентир длительности — Execution Time.

Уточните причину по буферам и статистике

BUFFERS дополняет время сведениями о доступе к данным. shared hit означает, что блок найден в общем буферном кэше PostgreSQL. shared read — что его прочитали в эти буферы, возможно из кэша ОС. Это количества обращений, а не обязательно уникальные блоки или физические чтения диска.

Большая ошибка оценки бывает связана с устаревшей статистикой или неравномерным распределением. Команда ANALYZE orders собирает статистику таблицы; это не то же самое, что EXPLAIN ANALYZE, который выполняет запрос. После массовых изменений сначала оцените статистику. Сортировка с выходом на диск и неверно оценённое соединение требуют разных действий.

ANALYZE orders;

Меняйте одно условие и сравнивайте честно

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

При сравнении сохраняйте сопоставимые параметры и данные. Повторяйте замеры: кэш и параллельная нагрузка меняют время, а один удачный прогретый запуск не доказывает универсальное ускорение. Учитывайте место под индекс и расходы при записи. Начинайте с безопасного SELECT в подходящей среде: EXPLAIN ANALYZE выполняет и изменяющие запросы, поэтому возможны побочные эффекты.

Что проверить

  • Различайте оценочные и фактические строки.
  • Учитывайте loops и объём работы.
  • Проверяйте статистику до изменения индексов.

Измерения зависят от данных, кеша и среды. Запускайте дорогой запрос только там, где его нагрузка допустима.

Источники

  1. PostgreSQL: using EXPLAIN ↗
  2. PostgreSQL: EXPLAIN command ↗
  3. PostgreSQL: performance tips ↗
  4. PostgreSQL: planner statistics ↗
Наверх ↑