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

Воркфлоу детектива

12 min
What you'll learn
  • складывать инструменты главы в один воркфлоу из пяти шагов
  • находить узел, где горит время, — с учётом loops и времени детей
  • отличать « ослеп» от «маршрут честный, но дорогой»
  • ставить полный диагноз отчёту из первого урока — и понимать, почему чинить его пока рано

Последняя вахта первой главы

Шесть ноль-ноль по станционному времени. Несколько вахт назад в этот самый час завис утренний отчёт — и КВЕРИ впервые открыл тебе люк на нижние палубы. С тех пор ты выучил язык чертежей: cost и rows, actual time и loops, страницы и Rows Removed, оценку против факта.

Сегодня новых инструментов не будет. Сегодня — порядок, в котором их достаёт инженер.

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

A workbench under a hooded lamp laid out like a detective's table: a rolled chalk plan, the brass stopwatch, a page-plate under a magnifier — and only at the end of the row an untouched wrench on its hook; a bin of unused brass index keys sits aside while the cadet keeps their hands behind their back, the robotic cat blocking the wrench and the parrot standing guard on the hook above.
Blueprint first, then the stopwatch, then the page map. The wrench comes last: an index applied blind is a cure without a diagnosis.

Пять шагов детектива

Когда запрос завис, инженер не «смотрит план» — инженер проходит по плану маршрутом, всегда одним и тем же.

Шаг 1. Сними полный чертёж: EXPLAIN (ANALYZE, BUFFERS). Один прогон — и все улики на руках: маршрут, реальное время, строки, страницы. Для SELECT это безопасно (про под ANALYZE ты помнишь ещё из Хранилища: он выполняется по-настоящему).

Шаг 2. Найди узел, где горит время. Не самый нижний и не самый страшный на вид, а узел с максимальным собственным временем: его actual time умножь на loops — приём из урока про хронометраж — и вычти время детей: время родителя всегда включает их время. Обычно девять десятых рейса сгорает в одном-двух узлах.

Шаг 3. Сверь оценку с фактом — est и actual — в этом узле. Est — то самое rows из первой скобки, прогноз штурмана; actual — факт из второй. Расхождение на порядок — ослеп: маршрут построен по неверным картам, и лечить надо карты, а не дорогу. Оценка сошлась — штурман всё видел и всё равно выбрал этот маршрут: дешевле по его модели не было, и думать надо о самой дороге.

Шаг 4. Посмотри, что прочитано зря: Rows Removed и Buffers. Сколько строк узел отбросил, едва прочитав, и сколько страниц поднял ради горстки нужных. Это перевод жалобы «медленно» на язык конкретных улик.

Шаг 5. Только теперь думай о починке. Индекс, переписанный запрос, обновлённые карты — лечение выбирают по диагнозу из шагов 2–4. Заметь, где стоит этот шаг: последним. Любая починка раньше этого шага — не починка, а гадание.

Карта чтения плана: полный чертёж → узел, где горит время → est против actual → Rows Removed и Buffers → и только потом починка

Дело №1: отчёт, который завис

Применим воркфлоу к делу, с которого началась глава. В первом уроке ты смотрел на этот запрос через простой — чертёж без рейса — и нашёл в дереве подозрительный SubPlan с полным проходом по журналу. Это было подозрение. Теперь собери доказательства.

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

Полный чертёж зависшего отчёта из первого урока — теперь с рейсом, секундомером и страницами. Найди в дереве SubPlan 1, а в нём Seq Scan on ls_readings: его loops, Rows Removed by Filter и Buffers — главные улики этого дела.

Шаги 2–5: диагноз

Шаг 2 — где горит. Наверху — Index Scan по первичному ключу датчиков (так штурман отдаёт строки сразу в порядке ORDER BY, даже узел Sort не понадобился). Время у него огромное, но почти всё это — время его детей. А вот Seq Scan on ls_readings внутри SubPlan: несколько миллисекунд на прогон — мелочь, пока не умножишь на loops=200. Двести прогонов съедают почти весь рейс. Собственное время — максимальное в дереве: узел найден.

Шаг 3 — est против actual. В горящем узле оценка rows=450, факт — rows=539 в среднем на прогон. Расхождение даже не в полтора раза — никакого «на порядок». Планировщик не ослеп: карты свежие, маршрут по ним построен честно. Чинить статистику бессмысленно — маршрут дорог сам по себе.

Шаг 4 — что прочитано зря. Rows Removed by Filter: 179461 — каждый прогон отбрасывает сто семьдесят девять тысяч строк журнала ради ~539 нужных. И Buffers: shared hit=302600 — та самая пачка из 1513 страниц, которую ты считал в уроке про BUFFERS, прочитанная двести раз подряд. (Внизу плана появились строки JIT — на дорогих маршрутах машина на лету компилирует части плана; для нашего диагноза они не важны.)

Шаг 5 — починка? Диагноз готов: запрос двести раз перечитывает весь журнал, потому что коррелированный, а читать журнал точечно машине нечем. Лечений минимум два — переписать запрос так, чтобы журнал читался один раз, или дать штурману короткую дорогу к показаниям одного датчика. Оба ты освоишь в следующих главах — сегодня ни одного индекса мы так и не создали, и это правильно. У тебя впервые есть не жалоба «медленно», а дело с уликами.

У люка

Вы с КВЕРИ поднимаетесь с нижних палуб. Гул машины за спиной теперь звучит иначе — не шум, а речь, которую ты начал разбирать.

КВЕРИ: Хорошая вахта. Ты читал план, как читает инженер: по шагам, без гаданий. Знаешь, в журнале планов «Котомаркета» мне однажды попался странный , который… Неважно. Старая вкладка. Считай, что я дремал.

Он замолкает на полуслове и слишком быстро меняет тему; хвост его процесса на мгновение застывает. Ты не переспрашиваешь. Пока.

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

Check yourself
Запрос завис. В каком порядке действует инженер?