Сорок секунд: первый EXPLAIN ANALYZE

Оценка против факта

12 min
O que você vai aprender
  • находить в плане главную пару чисел: rows в оценке и rows в факте
  • понимать, откуда у прогнозы: статистика, которую собирает команда ANALYZE
  • читать сигнал «карты устарели»: расхождение оценки и факта на порядок
  • старить статистику своими руками — и смотреть, как штурман слепнет

После вахты с буферами ты спускаешься в машинное отделение уже как к себе домой: люк, трап, ровный гул. КВЕРИ ждёт не у — у стойки в глубине зала, которую ты до сих пор принимал за архивный шкаф. Внутри — карты. Не палуб и не коридоров: карты данных. На верхнем листе — журнал жизнеобеспечения: сколько в нём строк, какие статусы встречаются на каждом шагу, какие — почти никогда. Штурман не заглядывает в сами данные, когда прокладывает маршрут: на это ушло бы больше времени, чем на сам рейс. Он смотрит сюда — в карты.

Ты вспоминаешь вчерашний план: в каждом узле стояло два rows — одно в первой паре скобок, другое во второй. Вчера они дружили: штурман обещал — и почти угадал.

КВЕРИ: Первое — то, что штурман ожидал по картам. Второе — то, что случилось в рейсе. Пока эти числа рядом, машина видит архив таким, какой он есть. Вопрос дня: что будет, когда они разойдутся?

A tall instrument panel where every gauge has two needles under one glass — chalk-white forecast and ember-orange fact; on the left the pairs nearly coincide, on the right one pair has split to the end of the scale and cracked the glass, the robotic cat staring at it from the panel ledge and the parrot perched on that gauge's rim.
Every node carries two readings. While forecast and fact sit together the plan can be trusted; the gap is where the fault lives.

Оценка и факт

Каждый узел плана под EXPLAIN ANALYZE несёт две пары скобок, и в каждой есть своё rows:

Seq Scan on ls_readings  (cost=0.00..3763.00 rows=<оценка> ...) (actual time=... rows=<факт> loops=1)
  • rows в оценке — сколько строк узел вернёт по прогнозу . Это число существует ещё ДО исполнения: из него складываются попугаи cost — тот самый ценник, по которому штурман сравнивает маршруты и берёт самый дешёвый. Ты видел его под чистым EXPLAIN.
  • rows в факте — сколько строк узел вернул на самом деле. Это число появляется только после рейса, его дописывает хронометраж.

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

Откуда берётся прогноз? Планировщик держит статистику — компактную карту каждой таблицы: сколько в ней строк, какие значения частые, какие редкие. Карту рисует команда ANALYZE <таблица>: она проходит по случайной выборке строк и перерисовывает её. Не путай с EXPLAIN ANALYZE — имена совпали, но инструменты разные: команда ANALYZE рисует карты, EXPLAIN ANALYZE исполняет запрос и показывает, что вышло.

Отсюда правило чтения — держи его под рукой весь курс:

Расхождение оценки и факта в разы — шум. Расхождение на ПОРЯДОК — сигнал. Прогноз из случайной выборки не обязан попадать строка в строку, а ошибиться вдвое для него — будни. Но если штурман ждал тысячу строк, а приехало двадцать тысяч, — маршрут выбран по неверной карте.

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

Two brackets on every node: the planner’s forecast and the stopwatch’s fact — the fault lives in the gap
Смотри на пару rows. Оценка — около девятисот, у каждого прогона своя, сотня-другая в ту или другую сторону: карты рисуются по случайной выборке, поэтому прогноз слегка дышит. Факт — ровно rows=900. Расхождение копеечное: карты свежие, штурман видит журнал таким, какой он есть.

Карты стареют

Статистика — , а не зеркало. Команда ANALYZE отсняла таблицу — и с этой секунды карта начинает отставать от территории: данные меняются, снимок — нет, до следующего ANALYZE. На карты пересобирает фоновый процесс, но приходит он по своему расписанию, когда изменений накопится достаточно, — а данные не ждут. Между «архив изменился» и «карты перерисованы» всегда есть окно. В этом окне слеп.

Устроим такое окно своими руками. Знакомься: датчик 13, самый шумный на станции, — на него и так приходится каждая пятая строка журнала. Сегодня он сорвался: каскадный сбой, и за одно утро в журнал упало двадцать тысяч fault-показаний. Ячейка ниже сама дописывает их в конец журнала и — не давая машине перерисовать карты — задаёт планировщику тот же вопрос об авариях:

Оценка осталась прежнего порядка — около тысячи: штурман смотрит в карту, снятую ДО каскада. (Она может выйти чуть выше, чем в прошлой ячейке: что журнал потолстел, штурман видит и без карты, — но долю аварий в нём он не пересчитывал.) Факт — rows=20900, в двадцать раз больше прогноза. Расхождение на порядок: планировщик ослеп. А Rows Removed by Filter: 179100 не изменилось: в отсев ушли те же старые строки — все двадцать тысяч новых показаний аварийные, и фильтр их пропускает.

Чем опасна старая карта

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

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

КВЕРИ: Заметь: машина не сломалась. Она честно исполнила лучший маршрут по той карте, что лежала на столе. Хочешь другой маршрут — принеси свежую карту.

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

Check yourself
Три узла из трёх разных планов. По паре rows (оценка → факт) найди узел, где планировщик ослеп: