# EXPLAIN и EXPLAIN ANALYZE: как читать план запроса

> Разбираем столбцы EXPLAIN в MySQL: type, key, rows, Extra. Отличие от EXPLAIN ANALYZE и признаки медленного запроса в плане выполнения.

## Что показывает EXPLAIN в MySQL

Команда `EXPLAIN` заставляет оптимизатор MySQL показать план выполнения запроса вместо того, чтобы его выполнять: какие таблицы читаются, в каком порядке, через какой индекс и сколько строк сервер планирует просмотреть. Без плана оптимизация запроса превращается в угадывание — EXPLAIN превращает её в проверку конкретных цифр.

План строится для SELECT, а также для UPDATE и DELETE — это удобно перед изменением большой таблицы, чтобы заранее увидеть, не уйдёт ли запрос в полное сканирование.

## Ключевые столбцы плана: type, key, rows, Extra

Из десятка столбцов EXPLAIN на практике важны четыре:

| Столбец | Что означает |
| --- | --- |
| type | Способ доступа к таблице: const, eq\_ref, ref, range, index, ALL |
| key | Индекс, который реально выбрал оптимизатор |
| rows | Оценка числа строк для просмотра на этом шаге |
| Extra | Пометки вроде Using filesort или Using temporary |
| key\_len | Сколько байт индекса реально участвует в поиске |

Значение `ALL` в столбце type означает полное сканирование таблицы без индекса. Для таблицы в пару тысяч строк это не страшно, а для таблицы на 10 миллионов строк — прямой путь к медленному запросу. Подробно о том, как индексы влияют на type и key, написано в статье про [оптимизацию индексов MySQL](https://www.zevshost.net/ru/kb/mysql-indeksy-optimizatsiya/).

## Чем EXPLAIN ANALYZE отличается от обычного EXPLAIN

Обычный EXPLAIN — это только предсказание оптимизатора, запрос не выполняется. `EXPLAIN ANALYZE`, доступный с MySQL 8.0.18, реально выполняет запрос и добавляет к плану фактическое время каждого шага и реальное число строк. Это позволяет сравнить прогноз с действительностью и найти шаг, где оценка оптимизатора разошлась с реальностью в разы.

Минус EXPLAIN ANALYZE — он выполняет запрос целиком, включая тяжёлые UPDATE. На проде такие проверки запускают на копии базы или в транзакции с последующим ROLLBACK.

## Как читать план на примере запроса с JOIN

Возьмём типичный запрос заказов с join к клиентам и посмотрим на вывод построчно.

```
EXPLAIN SELECT o.id, c.email
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'paid'
ORDER BY o.created_at DESC
LIMIT 20;
```

Если в строке для таблицы orders столбец type равен `ref`, а key указывает на индекс по status, оптимизатор нашёл нужные строки быстро. Если же type показывает `ALL`, а в Extra видно `Using where; Using filesort`, запрос сканирует всю таблицу и досортировывает результат в памяти или на диске — верный признак, что не хватает составного индекса по (status, created\_at).

## Частые проблемы, которые видно в плане

Несколько пометок в Extra почти всегда указывают на узкое место:

- `Using filesort` — сервер сортирует строки отдельно, индекс под ORDER BY не подошёл.
- `Using temporary` — для GROUP BY или DISTINCT создаётся временная таблица, часто на диске.
- `Using join buffer` — для JOIN не нашлось индекса, и MySQL перебирает строки в памяти.
- Большое значение rows на верхнем уровне плана при маленьком LIMIT в запросе.

## Как запустить EXPLAIN и EXPLAIN ANALYZE

Синтаксис одинаково прост для обеих команд:

```
EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE customer_id = 42;

EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42;
```

Формат JSON показывает больше деталей, включая стоимость каждого шага в условных единицах оптимизатора, и удобен для автоматических проверок в CI. Обычный табличный формат быстрее читается глазами при разовой диагностике. Найденные по плану медленные запросы удобно собирать через [slow query log](https://www.zevshost.net/ru/kb/mysql-slow-query-log/) и разбирать пачкой, а не по одному.

## Чек-лист оптимизации запроса по плану

Перед тем как закрыть тикет на медленный запрос, пройдитесь по пунктам:

- type для каждой таблицы в плане не хуже range, кроме заведомо маленьких справочников.
- key показывает реальный индекс, а не пусто.
- В Extra нет Using filesort и Using temporary на горячем пути.
- rows на верхнем уровне соразмерно ожидаемому результату, а не всей таблице.
- EXPLAIN ANALYZE подтвердил, что оценка rows близка к фактической.

## Частые вопросы

### В чём принципиальная разница между EXPLAIN и EXPLAIN ANALYZE?

Обычный EXPLAIN показывает только прогноз оптимизатора и не выполняет запрос, поэтому безопасен для любой таблицы. EXPLAIN ANALYZE реально запускает запрос и добавляет к плану фактическое время каждого шага и настоящее число строк, что позволяет увидеть, где оценка оптимизатора разошлась с действительностью, но требует осторожности с тяжёлыми операциями изменения данных.

### Насколько безопасно запускать EXPLAIN ANALYZE на рабочей базе данных?

EXPLAIN ANALYZE выполняет запрос по-настоящему, а не просто строит прогноз, поэтому для SELECT это обычно безвредно, а вот для UPDATE или DELETE запуск на проде рискован — реальные данные изменятся. Такие проверки принято делать на копии базы или внутри транзакции с последующим откатом, чтобы план посмотреть без последствий для данных.

### Почему оптимизатор иногда выбирает полное сканирование (ALL), даже если на нужном столбце есть индекс?

Индекс существует не значит, что он подойдёт именно этому запросу: оптимизатор смотрит на статистику таблицы и может решить, что просмотреть все строки дешевле, чем использовать индекс низкой избирательности, то есть такой, где значение повторяется почти в каждой строке. Часто дело также в устаревшей статистике или отсутствии нужного составного индекса под конкретные условия WHERE и ORDER BY.

### Если план показывает Using filesort, обязательно ли сразу добавлять индекс?

Не всегда: пометка Using filesort означает, что сервер досортировывает строки отдельно, но для маленькой выборки это недорогая операция и не заметна по времени ответа. Добавлять составной индекс под ORDER BY стоит, когда это сочетается с большим rows на верхнем уровне плана или с ростом времени ответа запроса по мере роста таблицы.

---

Источник: https://www.zevshost.net/ru/kb/mysql-explain-plan-zaprosa/
