Чтение плана EXPLAIN
Интерпретация типов сканирования, методов соединения и оценок стоимости в плане запроса
«Чтение плана EXPLAIN» — бесплатный урок Coding Interview Prep на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Coding Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Coding Interview Prep содержит 4 уроков всего.
Почему на собеседовании спрашивают про EXPLAIN
Когда Вы доходите до собеседования на позицию старшего уровня, интервьюеры перестают просить написать запрос и начинают спрашивать: почему этот запрос работает медленно. Ответить на этот вопрос помогает инструмент EXPLAIN.
EXPLAIN показывает план выполнения базы данных: пошаговую стратегию, которую планировщик выбрал для выполнения Вашего SQL-запроса. Он показывает, какие таблицы сканируются, в каком порядке они соединяются и насколько приблизительно затратен каждый шаг.
Умение читать план показывает, что Вы понимаете работу ядра базы данных, а не только синтаксис. Именно это интервьюеры используют, чтобы отличить специалиста среднего уровня от специалиста старшего уровня.
EXPLAIN и EXPLAIN ANALYZE
Существуют два варианта, и интервьюеры любят проверять, понимаете ли Вы разницу.
- EXPLAIN показывает оценочный план планировщика, не выполняя запрос. Это быстро и безопасно.
- EXPLAIN ANALYZE действительно выполняет запрос и сообщает фактическое количество строк и время выполнения вместе с оценочными значениями.
Самое ценное — сравнить оценочное и фактическое количество строк. Большое расхождение означает, что у планировщика нет точной статистики и он, скорее всего, принимает неудачное решение.
Внимание: EXPLAIN ANALYZE действительно выполняет запрос, поэтому он выполнит любые операции INSERT или UPDATE, если запрос не заключён в транзакцию с последующим откатом.
EXPLAIN ANALYZE
SELECT * FROM orders WHERE customer_id = 42;Как читать дерево
План — это дерево, а не список. Наиболее глубоко отступившие узлы — это конечные узлы, которые выполняются первыми; результаты поднимаются к корню, формирующему окончательный вывод.
Читайте план изнутри наружу: найдите самый глубокий узел — именно с него начинается выполнение. Каждый родительский узел получает строки, созданные его дочерними узлами.
На собеседовании объясняйте это так: сначала мы сканируем эту таблицу, затем эти строки поступают в это соединение, соединение передаёт их сортировке, а сортировка — ограничению. Именно такое объяснение снизу вверх хотят от Вас услышать.
Анатомия узла плана
Каждый узел плана Postgres содержит одни и те же основные числовые показатели:
- стоимость=0.00..35.50 стоимость запуска…общая стоимость в условных единицах планировщика
- строки=1000 оценочное число созданных строк
- ширина=64 оценочный средний размер строки в байтах
Первая стоимость — это стоимость запуска (работа до появления первой строки, например построение хеш-таблицы). Вторая — общая стоимость возврата всех строк. Чем выше общая стоимость, тем выше, по оценке планировщика, относительная затратность.
Seq Scan on orders (cost=0.00..35.50 rows=1000 width=64)Практический пример
Рассмотрим простой запрос с фильтрацией. Приведённый ниже план в одной строке описывает происходящее.
Это последовательное сканирование (полное чтение таблицы) таблицы orders с применением фильтра status = 'shipped'. Планировщик оценивает число совпадающих строк в 1000.
Если в orders содержится 10 миллионов строк, а совпадает только 1000, на собеседовании от Вас ожидают такой формулировки: последовательное сканирование здесь неэффективно; индекс по status (или по более избирательному столбцу) позволит не читать всю таблицу целиком.
EXPLAIN SELECT * FROM orders WHERE status = 'shipped';
Seq Scan on orders (cost=0.00..18334.00 rows=1000 width=64)
Filter: (status = 'shipped'::text)Оценочное и фактическое число строк
С помощью EXPLAIN ANALYZE Вы также получите фактические значения в скобках.
Посмотрите на пример: планировщик оценил число строк в 1000, но фактически получил 480000. Это занижение оценки в 480 раз. Планировщик выбрал стратегию, предполагая небольшое число строк, поэтому для реальных данных его выбор, вероятно, неверен.
На собеседовании этот разрыв — главный диагностический вывод: статистические данные устарели; выполните ANALYZE для таблицы, после чего планировщик, скорее всего, выберет более подходящий план.
Seq Scan on orders
(cost=0.00..18334.00 rows=1000 width=64)
(actual time=0.02..210.4 rows=480000 loops=1)Что означает циклы=N
Значение loops важнее, чем ожидают многие кандидаты. Это число раз, которое был выполнен узел.
Оно появляется на внутренней стороне соединения вложенным циклом: внутренний узел запускается для каждой строки внешней стороны. Если loops=480000, этот внутренний шаг выполнился 480 тысяч раз.
Важно: показанные время на строку и число строк указаны для одного цикла. Чтобы получить настоящее общее значение, умножьте его на loops. Узел, который выглядит дешёвым при стоимости 0.004 мс за цикл, за 480000 циклов занимает почти 2 секунды.
Index Scan using idx_cust on orders
(actual time=0.003..0.004 rows=1 loops=480000)Стоимость относительна, а не выражается в миллисекундах
Распространённая ловушка: кандидаты видят cost=18334 и говорят: это занимает 18 секунд. Неверно.
Стоимость указывается в условных единицах планировщика, откалиброванных так, что одно последовательное чтение страницы равно 1.0. Она имеет смысл только для сравнения планов между собой, а не как показатель реального времени выполнения.
Для измерения реального времени нужны EXPLAIN ANALYZE и значения actual time, измеряемые в миллисекундах. Чётко скажите это на собеседовании: так Вы покажете, что действительно понимаете этот показатель.
Чтение плана соединения
Перед Вами план для двух таблиц. Читайте его снизу вверх.
Сначала два сканирования получают строки из orders и customers. Они передают их в хеш-соединение: одна сторона хешируется, а другая выполняет поиск по хешу. Затем результат соединения передаётся дальше для формирования итогового результата.
Обратите внимание: отступы показывают структуру — оба сканирования находятся под хеш-соединением. Интервьюер хочет, чтобы Вы назвали метод соединения (здесь хеш-соединение) и указали, какая таблица хешируется (обычно меньшая).
Hash Join (cost=30.0..520.0 rows=900 width=72)
Hash Cond: (o.customer_id = c.id)
-> Seq Scan on orders o (cost=0..400 rows=10000)
-> Hash (cost=18..18 rows=500)
-> Seq Scan on customers c (cost=0..18 rows=500)Тревожные признаки, на которые стоит указать
Научитесь замечать эти предупреждающие признаки в любом плане:
- Последовательное сканирование большой таблицы с избирательным фильтром — здесь может помочь индекс.
- Оценочное число строк сильно отличается от фактического — статистика устарела.
- Соединение вложенным циклом с большим числом циклов для большой таблицы — часто это означает отсутствие индекса по ключу внутреннего соединения.
- Выгрузка сортировки или хеша на диск (показывается как использование
Disk) — значениеwork_memслишком мало. - Очень большое число строк, удалённых фильтром — Вы прочитали и отбросили большую часть таблицы.
Форматы вывода и BUFFERS
Планы бывают в нескольких форматах. Формат по умолчанию TEXT — это то, что обычно зачитывают на собеседовании. Но можно запросить и структурированный вывод.
EXPLAIN (FORMAT JSON) или FORMAT YAML создаёт машиночитаемые планы, которые разбирают инструменты и панели мониторинга. Вручную они нужны редко, но знание об их существовании — хороший признак опытного специалиста.
Добавляйте параметры в скобках: EXPLAIN (ANALYZE, BUFFERS). Параметр BUFFERS показывает попадания в кэш и чтения с диска — это особенно полезно для диагностики запросов, ограниченных скоростью ввода-вывода.
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE customer_id = 42;Быстрая проверка
Интервьюер показывает Вам узел EXPLAIN ANALYZE, где в разделе стоимости указано rows=1000, а значение actual ... rows=480000. Каков наиболее вероятный диагноз?
Итоги
Теперь Вы умеете читать план как опытный специалист:
EXPLAINстроит оценки, аEXPLAIN ANALYZEвыполняет запрос и измеряет результаты.- Читайте дерево снизу вверх: сначала выполняются листья, а корень формирует вывод.
- Каждый узел показывает стоимость (относительные единицы), число строк и ширину;
actual time— это реальное значение в миллисекундах. loopsумножает значения для одного цикла, поэтому следите за вложенными циклами.- Разрыв между оценочным и фактическим числом строк — Ваш главный диагностический сигнал.
Озвучивайте план вслух и отмечайте тревожные признаки — именно так ведёт себя сильный кандидат на собеседовании.
Часто задаваемые вопросы
Урок «Чтение плана EXPLAIN» бесплатный?
Да — полный текст урока «Чтение плана EXPLAIN» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Coding Interview Prep, подпишись на CoddyKit PRO. Курс Coding Interview Prep содержит 4 уроков всего.
Чему я научусь в уроке «Чтение плана EXPLAIN»?
Интерпретация типов сканирования, методов соединения и оценок стоимости в плане запроса Ты практикуешь Coding Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Coding Interview Prep?
Предыдущий опыт не требуется. Coding Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Чтение плана EXPLAIN»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Coding Interview Prep?
Да. Каждый урок Coding Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Чтение плана EXPLAIN
- Последовательное, индексное и покрывающее сканирование
- Алгоритмы соединения: вложенный цикл, хеширование и слияние
- Поиск и исправление медленных запросов