Урок 10.3 · Время чтения: ~9 мин
Этот урок познакомит вас с инструментами анализа SQL-запросов и способами их оптимизации. Вы узнаете, как «читает» ваш код база данных, что такое план выполнения и как находить «узкие места» в сложных выборках. Мы разберем практическое использование команды EXPLAIN и научимся интерпретировать ее результаты. К концу урока вы сможете не просто писать запросы, но и профессионально диагностировать причины их медленной работы.
В предыдущем уроке мы разобрали базовые правила написания эффективного кода. Но что делать, если запрос все равно работает медленно? Чтобы решить проблему производительности, нужно перестать гадать и начать анализировать. Каждый раз, когда вы отправляете запрос базе данных, специальный компонент СУБД — оптимизатор — строит план его выполнения.
Понимание того, как именно СУБД собирается извлекать данные, является ключом к глубокой оптимизации. В этом уроке мы научимся заглядывать во «внутреннюю кухню» сервера, используя основной инструмент разработчика — план выполнения.
План выполнения — это подробная инструкция, которую составляет СУБД для выполнения конкретного SQL-запроса. В нем описывается:
cost) выполнения каждой операции.EXPLAINПрактически во всех реляционных СУБД (MySQL, PostgreSQL, MariaDB) основной командой для анализа плана является EXPLAIN.
Достаточно добавить слово EXPLAIN в начало вашего запроса:
EXPLAIN
SELECT customer_id, first_name, last_name
FROM customer
WHERE active = 1;
Результат: СУБД вернет таблицу, где каждая строка описывает этап выполнения запроса.
При чтении вывода EXPLAIN критически важны следующие поля:
type или access_type)Это поле показывает, как СУБД ищет строки:
const / eq_ref: Идеально. Поиск по уникальному ключу (одна строка).ref: Очень хорошо. Поиск по индексу, который может вернуть несколько строк.range: Хорошо. Поиск по диапазону значений в индексе (например, BETWEEN или >).index: Посредственно. Полное сканирование индекса.ALL: Опасно. Полное сканирование таблицы (Full Table Scan). Если таблица большая, это причина тормозов.key / possible_keys)Здесь можно увидеть, какой индекс был выбран оптимизатором. Если в поле key стоит NULL, значит, СУБД не нашла подходящего индекса и сканирует всю таблицу.
rows)Это оценочное количество строк, которое СУБД придется проверить для выполнения запроса. Чем меньше это число, тем быстрее отработает запрос.
Допустим, у нас есть запрос для поиска платежей за конкретный день:
EXPLAIN
SELECT *
FROM payment
WHERE payment_date = '2005-05-25 11:30:37';
Если в колонке type вы видите ALL, а в key — NULL, значит, индекс по дате отсутствует или не используется.
Решение:
Обычно решением является создание индекса по полю, используемому в WHERE. О самих индексах мы подробно поговорим в следующем уроке, но именно EXPLAIN позволяет увидеть необходимость их создания.
JOIN позволяет оптимизатору построить более эффективный план.DISTINCT или ORDER BY в подзапросах блокируют возможности оптимизации.Ключевые выводы этого урока:
EXPLAIN, чтобы увидеть, как именно база данных ищет данные.ALL (Full Table Scan) на больших таблицах.rows помогает оценить масштаб работы, которую предстоит выполнить серверу.key равен NULL), это повод проверить SARGable-условия или наличие индекса.EXPLAIN, если запрос и так работает?EXPLAIN помогает увидеть потенциальные проблемы до того, как объем данных вырастет. Запрос может быть «достаточно быстрым» сегодня, но его план уже может содержать признаки будущих узких мест.
На больших таблицах тревожный сигнал — тип доступа ALL, который означает полное сканирование. Это не всегда ошибка, но чаще всего повод проверить индексы, условия фильтрации и форму запроса.
rows важно при анализе?rows показывает, сколько строк СУБД ожидает проверить на этапе плана. Большие значения обычно указывают на избыточную работу и помогают быстро найти участок, который нужно оптимизировать в первую очередь.
План выполнения — это стратегия, которую строит оптимизатор СУБД для получения результата запроса. В плане видно порядок операций, методы доступа к данным и оценочную стоимость каждого шага.
EXPLAIN вы проверяете в первую очередь и почему?Сначала смотрю на type/access_type, key/possible_keys и rows. Эти поля быстро показывают, использует ли запрос индексы, как именно читаются данные и где может быть основная нагрузка.
EXPLAIN, что нужен индекс?Если в key часто NULL, а type указывает на полный скан, это сигнал проверить индексирование полей из WHERE и JOIN. После добавления индекса полезно повторить EXPLAIN и сравнить план до и после.
В следующем уроке мы перейдем к самому мощному инструменту ускорения — индексам, и научимся создавать их правильно.