awesome-everything EN
↑ Обратно к восхождению

Базы данных

EXPLAIN и планы выполнения: что решает планировщик и почему

Суть Plan выполнения — это дерево операций, которое Postgres выбирает для запроса. EXPLAIN показывает план; EXPLAIN ANALYZE запускает запрос и показывает реальные тайминги. Rows-estimated vs rows-actual — самое информативное число в выводе.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на junior-высоте — поверхность
◷ 12 min

Dashboard-запрос занимает 6 секунд в production. Коллега спрашивает: «ты делал EXPLAIN?». Запускаешь EXPLAIN ANALYZE — и через две секунды видишь Seq Scan on orders ... actual rows=80000000. Один индекс. 200 мс. Вот для чего нужен EXPLAIN.

Что такое план выполнения

SQL декларативен — вы описываете какие строки хотите получить, а не как их извлечь. Планировщик Postgres заполняет этот пробел. Он читает SQL, обращается к pg_statistic, чтобы оценить количество строк для каждого условия, перебирает возможные комбинации типов сканирования и алгоритмов соединения, вычисляет стоимость каждого варианта и выбирает дешевейший. Результат — план — дерево операторов с прикреплёнными к ним оценками строк.

Запрос проходит четыре этапа до возврата первой строки:

  1. Парсинг — текст преобразуется в дерево разбора
  2. Переписывание — применяются правила и представления
  3. Планирование — планировщик строит дешевейшее дерево выполнения
  4. Исполнение — движок выполняет дерево

Единственный этап, который вы настраиваете, — это планирование. Всё остальное автоматично.

КомандаВыполняет запрос?Показывает
EXPLAINНетОценку планировщика: стоимости, количество строк, форму плана
EXPLAIN ANALYZEДаОценки + реальные тайминги, реальные строки, loops
EXPLAIN (ANALYZE, BUFFERS)ДаВсё вышеперечисленное + счётчики обращений к кешу страниц

Чтение вывода

Простой план выглядит так:

Index Scan using idx_orders_workspace on orders
  (cost=0.43..14.2 rows=42 width=120)
  (actual time=0.08..1.1 rows=42 loops=1)
  Index Cond: (workspace_id = 42)
  • cost=0.43..14.2 — стоимость запуска (первая строка) и полная стоимость в произвольных единицах. Не миллисекунды. Важны соотношения; абсолютные значения без контекста бессмысленны.
  • rows=42 — оценка планировщика: сколько строк выдаст этот узел
  • actual rows=42 — реально выданных строк во время выполнения
  • loops=1 — сколько раз выполнялся этот узел (важно внутри соединений)

Диагностическое правило: сравнивайте rows (оценка) с actual rows (реальность). Разрыв в 10× — подозрительно. Разрыв в 1000× — вот почему запрос занимает 8 минут вместо 50 мс.

Метафора GPS

EXPLAIN — это предпросмотр маршрута в GPS перед поездкой. EXPLAIN ANALYZE — видеозапись реальной поездки с видеорегистратора. Предпросмотр говорит «маршрут займёт 12 минут» — это оценка по картам. Видеозапись говорит «поездка заняла 47 минут из-за пробок, которых не было на карте». Разрыв между оценкой и реальностью — это именно то место, где вы вмешиваетесь: плохие карты (устаревшая статистика) приводят к плохому выбору маршрута; плохие датчики (нет индекса для условия) делают поездку медленнее, чем обещал маршрут.

Конкретный сценарий: поиск узкого места

Поисковый запрос команды занимает 200 мс на staging и 8 секунд в production. EXPLAIN ANALYZE показывает:

Hash Join  (cost=2400..55000 rows=50000)
            (actual time=7800..8050 rows=42)
  Hash Batches: 64  Memory Usage: 2.1GB

Batches: 64 означает, что хеш-таблица 64 раза сбрасывалась на диск — результат того, что work_mem слишком мал для реального размера соединения. Исправление: SET work_mem = '64MB'. Тот же запрос — 220 мс. Один EXPLAIN, одно изменение конфигурации.

Почему это работает

EXPLAIN ANALYZE реально выполняет запрос. Для SELECT это всегда безопасно. Для UPDATE или DELETE оберните в транзакцию и откатите: BEGIN; EXPLAIN ANALYZE DELETE ...; ROLLBACK;. Запрос выполнится (вы увидите реальные тайминги), но изменения будут отменены.

Расставь шаги по порядку

Упорядочьте шаги, которые разработчик должен выполнить при неожиданно медленном запросе:

  1. 1 Воспроизвести медлительность с репрезентативным запросом и параметрами
  2. 2 Запустить EXPLAIN ANALYZE (в транзакции, если запрос модифицирует данные)
  3. 3 Найти узел плана, занимающий наибольшее реальное время
  4. 4 Сравнить rows estimated vs actual на каждом узле — большой разрыв означает устаревшую статистику
  5. 5 Выбрать исправление: ANALYZE таблицы, добавить или изменить индекс, переписать запрос
  6. 6 Применить исправление и повторно запустить EXPLAIN ANALYZE для подтверждения улучшения
  7. 7 Добавить регрессионный тест, чтобы медленный запрос не вернулся
Викторина

В чём разница между EXPLAIN и EXPLAIN ANALYZE?

Викторина

В выводе EXPLAIN ANALYZE вы видите `rows=10 ... actual rows=1240000`. Что это означает?

Закончи аналогию

Заполните пропуск: EXPLAIN относится к SQL-запросу так же, как ________ к путешествию — запланированный маршрут, продолжительности и пересадки, распечатанные до реальной поездки.

Вспомните перед уходом
  1. 01
    Двумя предложениями: что такое план выполнения и зачем он нужен Postgres?
  2. 02
    Что означают 'actual rows' vs 'rows' в выводе EXPLAIN ANALYZE и почему большое расхождение важно?
  3. 03
    Когда НЕ нужно запускать EXPLAIN ANALYZE на запросе и как это обойти?
Итог

План выполнения — это дерево операций, которое Postgres строит для ответа на SQL-запрос, выбирая среди типов сканирования, алгоритмов соединения и стратегий агрегации на основе оценок стоимости из табличной статистики. EXPLAIN печатает план без выполнения; EXPLAIN ANALYZE выполняет запрос и добавляет реальные тайминги, реальные счётчики строк и реальные loops. Самое диагностически ценное число — разрыв между rows (оценка) и actual rows (реальность) на каждом узле: недооценка в 1000× распространяется вверх и делает неверным каждый выбор соединения и сортировки выше неё. Каждое расследование медленного запроса начинается с EXPLAIN ANALYZE и сравнения rows-estimated vs actual.

Практика

Сделай это, чтобы превратить узнавание в навык.

Связанные уроки
встречается в174
Продолжить восхождение ↑Типы сканирования: Seq, Index, Bitmap, Index-Only
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.