← Назад к вопросам

Какие знаешь поля у explain?

2.0 Middle🔥 132 комментариев
#Базы данных и SQL

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Анализ полей EXPLAIN в MySQL

EXPLAIN (или его более современный аналог EXPLAIN FORMAT=JSON) — ключевой инструмент для анализа и оптимизации запросов в MySQL. Его вывод представляет собой таблицу с набором полей, каждый из которых раскрывает определенный этап выполнения запроса. Знание этих полей критически важно для понимания плана выполнения и поиска узких мест.

Основные поля стандартного EXPLAIN

В стандартном текстовом выводе EXPLAIN содержатся следующие колонки:

  1. id: Уникальный идентификатор каждого шага в плане выполнения. Если id одинаковый для нескольких строк — это означает, что шаги выполняются вместе (например, в подзапросе). Значение NULL может указывать на объединение результатов.

  2. select_type: Тип операции SELECT. Это поле говорит о том, как запрос был разбит на части.

    *   **`SIMPLE`**: Простой запрос без подзапросов или `UNION`.
    *   **`PRIMARY`**: Основной запрос в конструкции с `UNION` или подзапросе.
    *   **`SUBQUERY`**: Первый подзапрос в `SELECT`.
    *   **`DERIVED`**: Подзапрос в `FROM`, результат которого материализуется в временную таблицу.
    *   **`UNION`**: Второй и последующие запросы в `UNION`.
    *   **`UNION RESULT`**: Оператор, объединяющий результаты `UNION`.

  1. table: Имя таблицы, к которой относится данный шаг. Это может быть реальная таблица, временная таблица (например, derived2) или даже NULL в некоторых случаях объединения.

  2. partitions: Показывает, какие разделы (partitions) таблицы будут использоваться в запросе. Если таблица не разделена, значение будет NULL.

  3. type: Это одно из самых важных полей. Оно описывает тип соединения (join type) или способ доступа к данным в таблице. От худшего к лучшему:

    *   **`ALL`**: Полное сканирование таблицы (full table scan). Самый медленный тип.
    *   **`index`**: Полное сканирование, но по индексному дереву (иногда бывает быстрее `ALL`, если нужны только данные из индекса).
    *   **`range`**: Сканирование по диапазону значений индекса (например, `WHERE id > 10`).
    *   **`ref`**: Доступ через не-уникальный индекс, где используется равенство (`=`).
    *   **`eq_ref`**: Доступ через уникальный индекс в соединении (каждый ряд из первой таблицы соответствует только одному ряду из второй).
    *   **`const`**: Таблица читается один раз, потому что найдена одна строка по уникальному индексу с константой (`WHERE id = 5`).
    *   **`system`**: Особый случай `const`, когда таблица имеет только одну строку.

  1. possible_keys: Список индексов, которые теоретически могут быть использованы для этого шага. Если здесь NULL — возможно, нужно добавить индекс.

  2. key: Индекс, который фактически был выбран оптимизатором для использования.

  3. key_len: Длина используемой части ключа (в байтах). Полезно для понимания, сколько колонок индекса реально используется. Например, для составного индекса (a, b, c) и условия WHERE a = 1, key_len будет равна длине только колонки a.

  4. ref: Показывает, какие колонки или константы сравниваются с индексом (key). Например:

    -- В EXPLAIN для таблицы t2 может быть: ref = 't1.id'
    SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id;
    
  5. rows: Оценочное количество строк, которое MySQL придется обработать на этом шаге для получения результата. Ключевой показатель для оценки эффективности. Большое число (> 1000) часто указывает на проблему.

  6. filtered: Процент строк (от оценочного rows), которые будут отфильтрованы последующими условиями (например, из WHERE). Значение от 0 до 100. Низкий процент (например, 10%) означает, что большинство просмотренных строк будут отброшены — это может быть признаком неэффективности.

  7. Extra: Дополнительная информация о том, как выполняется шаг. Здесь могут быть очень важные указания:

    *   **`Using where`**: Условие `WHERE` применяется после чтения строки (фильтрация на уровне сервера).
    *   **`Using index`**: Запрос использует только данные из индекса (покрывающий индекс — **covering index**), без обращения к самой таблице. Это очень эффективно.
    *   **`Using temporary`**: MySQL создает временную таблицу для обработки запроса (часто при `GROUP BY`, `ORDER BY` без подходящего индекса). Требует оптимизации.
    *   **`Using filesort`**: Для сортировки требуется дополнительный проход и, возможно, сортировка в файле (в памяти или на диске). Также часто указывает на проблему с `ORDER BY`.
    *   **`Using join buffer`**: Для соединения используется буфер, потому что нет подходящего индекса (обычно для `Block Nested Loop`).

Пример анализа через EXPLAIN FORMAT=JSON

Для более глубокого анализа лучше использовать EXPLAIN FORMAT=JSON. Он предоставляет гораздо больше деталей: стоимость запроса (query_cost), информацию о использованных индексах (used_key_parts), данные о подзапросах и преобразованиях.

EXPLAIN FORMAT=JSON SELECT * FROM users WHERE email = 'test@example.com';

Вывод будет содержать nested JSON с полями, аналогичными вышеописанным, но в более структурированной форме, включая блок cost_info и детализацию для каждого шага выполнения (table, access_type, rows_examined_per_scan).

Практическое применение

Анализируя поля EXPLAIN, можно:

  • Найти полные сканирования таблиц (type: ALL) и добавить необходимые индексы.
  • Определить неэффективные соединения по высокому значению rows и низкому filtered.
  • Увидеть проблемы сортировки и группировки (Using temporary, Using filesort) и попытаться устранить их путем добавления индексов на поля ORDER BY/GROUP BY.
  • Проверить эффективность использования индексов через key, key_len и Using index.
  • Сравнить планы выполнения до и после оптимизации, чтобы убедиться в улучшениях.

Таким образом, глубокое понимание полей EXPLAIN — это фундамент для профессиональной работы с производительностью баз данных и написания эффективного SQL-кода.