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

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

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

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

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

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

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

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

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

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

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

У люка

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

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

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

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

Проверь себя
Запрос завис. В каком порядке действует инженер?
Закрепление: реши задачи
Решено 0 из 2