Spec-Zone.ru › MariaDB

EXPLAIN

Синтаксис

EXPLAIN tbl_name [col_name | wild]

Или

EXPLAIN [EXTENDED | PARTITIONS | FORMAT=JSON] 
  {SELECT select_options | UPDATE update_options | DELETE delete_options}

Описание

Оператор EXPLAIN может использоваться как синоним для DESCRIBE, а также для получения информации о том, как MariaDB выполняет оператор SELECT, UPDATE или DELETE:

  • 'EXPLAIN tbl_name' является синонимом для 'DESCRIBE tbl_name' или 'SHOW COLUMNS FROM tbl_name'.
  • При добавлении ключевого слова EXPLAIN перед оператором SELECT, UPDATE или DELETE, MariaDB отображает информацию из оптимизатора о плане выполнения запроса. То есть, MariaDB объясняет, как он обработает оператор SELECT, UPDATE или DELETE, включая информацию о том, как и в каком порядке таблицы объединяются. EXPLAIN EXTENDED может использоваться для предоставления дополнительной информации.
  • EXPLAIN PARTITIONS полезен только при рассмотрении запросов, включающих разнесённые таблицы.
    Для получения подробностей см. Обрезка и выборка разнесений.
  • Оператор ANALYZE выполняет запрос и выводит результат EXPLAIN, а также предоставляет фактические и оценочные статистические данные.
  • Результат EXPLAIN может быть выведен в журнале медленных запросов. Подробности см. в EXPLAIN в журнале медленных запросов.

SHOW EXPLAIN отображает вывод выполняемого оператора. В некоторых случаях его вывод может быть ближе к реальности, чем EXPLAIN.

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

Существует онлайн EXPLAIN-анализатор, который вы можете использовать для совместного использования вывода EXPLAIN и EXPLAIN EXTENDED с другими пользователями.

EXPLAIN может получать метаданные блокировки аналогично SELECT, так как ему необходима информация о метаданных таблиц и, иногда, о данных.

Столбцы в EXPLAIN ... SELECT

Имя столбца Описание
id Порядковый номер, отображающий порядок объединения таблиц.
select_type Тип источника таблицы.
table Псевдоним таблицы. Материализованные временные таблицы для подзапросов имеют имена <подзапрос#>
type Тип объединения строк.
possible_keys Ключи таблицы, которые могут использоваться для поиска строк.
key Имя используемого ключа. NULL если ключ не был использован.
key_len Количество байтов используемого ключа (показывает, используем ли мы только части составного ключа).
ref Ссылка, используемая как значение ключа.
rows Оценка количества строк, которые будут найдены в таблице для каждого поиска по ключу.
Extra Дополнительная информация об объединении.

Ниже приведены описания значений некоторых более сложных столбцов в EXPLAIN ... SELECT:

Столбец "Select_type"

Столбец select_type может содержать следующие значения:

Значение Описание Примечание
DEPENDENT SUBQUERY SUBQUERY является DEPENDENT
DEPENDENT UNION UNION является DEPENDENT
DERIVED SELECT является DERIVED из PRIMARY
MATERIALIZED SUBQUERY является MATERIALIZED Материализованные таблицы заполняются при первом обращении и будут обращаться по первичному ключу (= один поиск по ключу). Число строк в EXPLAIN показывает затраты на заполнение таблицы
PRIMARY SELECT находится в самом внешнем запросе, но также есть SUBQUERY внутри него.
SIMPLE Это простой запрос SELECT без каких-либо SUBQUERY или UNION.
SUBQUERY SELECT является SUBQUERY PRIMARY
UNCACHEABLE SUBQUERY SUBQUERY является UNCACHEABLE
UNCACHEABLE UNION UNION является UNCACHEABLE
UNION SELECT является UNION PRIMARY
UNION RESULT Результат UNION
LATERAL DERIVED SELECT использует латеральную оптимизацию производных выражений

Столбец "Type"

Этот столбец содержит информацию о том, как осуществляется доступ к таблице.

Значение Описание
ALL Производится полный сканирование таблицы (читаются все строки). Это плохо, если таблица большая, и она объединяется с предыдущей таблицей! Это происходит, когда оптимизатор не смог найти полезный индекс для доступа к строкам.
const В таблице может быть только одна соответствующая строка. Строка читается до фазы оптимизации, и все столбцы таблицы рассматриваются как константы.
eq_ref Используется уникальный индекс для поиска строк. Это лучший возможный план для поиска строки.
fulltext Используется полнотекстовый индекс для доступа к строкам.
index_merge Производится поиск по нескольким индексам в диапазоне, и найденные строки объединяются. Столбец "Ключ" показывает, какие ключи используются.
index_subquery Аналогично ref, но используется для подзапросов, которые преобразуются в поиск по ключу.
index Полное сканирование по используемому индексу. Лучше, чем ALL, но по-прежнему плохо, если индекс большой, и таблица объединяется с предыдущей таблицей.
range Таблица будет обработана с помощью ключа по одному или нескольким диапазонам значений.
ref_or_null Как ref, но дополнительно выполняется поиск значения null, если первое значение не найдено. Это обычно происходит с подзапросами.
ref Используется неуникальный индекс или префикс уникального индекса для поиска строк. Хорошо, если префикс не соответствует многим строкам.
system Таблица содержит 0 или 1 строку.
unique_subquery Аналогично eq_ref, но используется для подзапросов, которые преобразуются в поиск по ключу

Столбец "Extra"

Этот столбец состоит из одного или нескольких следующих значений, разделенных точкой с запятой

Обратите внимание, что некоторые из этих значений обнаруживаются после фазы оптимизации.

Фаза оптимизации может внести следующие изменения в WHERE:

  • Добавить выражения из ON и USING в WHERE.
  • Распространение констант: Если существует column=constant, заменить все вхождения столбца этой константой.
  • Заменить все столбцы из таблиц 'const' их значениями.
  • Удалить используемые столбцы ключа из WHERE (так как они будут проверены в рамках поиска по ключу).
  • Удалить невозможные константные подвыражения. Например, WHERE '(a=1 and a=2) OR b=1' становится 'b=1'.
  • Заменить столбцы другими столбцами, имеющими идентичные значения: Пример: WHERE a=b и a=c могут рассматриваться как 'WHERE a=b and a=c and b=c'.
  • Добавить дополнительные условия для обнаружения невозможных условий строк ранее. Это происходит в основном с OUTER JOIN, где в некоторых случаях мы добавляем обнаружение NULL значений в WHERE (часть оптимизации 'Not exists'). Это может привести к неожиданному значению 'Using where' в столбце Extra.
  • Для каждого уровня таблицы мы удаляем выражения, которые уже были проверены при чтении предыдущей строки. Например, при объединении таблиц t1 с t2 с помощью WHERE 't1.a=1 and t1.a=t2.b', мы не должны проверять 't1.a=1' при проверке строк в t2, так как мы уже знаем, что это выражение истинно.
Значение Описание
const row not found Таблица была системной таблицей (таблица с ровно одной строкой), но строка не найдена.
Distinct Если использовалась оптимизация по уникальным значениям (удаление дубликатов). Это отмечается только для последней таблицы в SELECT.
Full scan on NULL key Таблица является частью подзапроса, и если значение, используемое для сопоставления с подзапросом, будет NULL, мы выполним полное сканирование таблицы.
Impossible HAVING Используемый HAVING-оператор всегда ложный, поэтому SELECT не вернёт ни одной строки.
Impossible WHERE noticed after reading const tables. Используемый WHERE-оператор всегда ложный, поэтому SELECT не вернёт ни одной строки. Этот случай был обнаружен после того, как мы прочитали все таблицы 'const' и использовали значения столбцов в качестве констант в WHERE-оператор. Например: WHERE const_column=5 и const_column имели значение 4.
Impossible WHERE Используемый WHERE-оператор всегда ложный, поэтому SELECT не вернёт ни одной строки. Например: WHERE 1=2
No matching min/max row Во время ранней оптимизации значений MIN()/MAX() было обнаружено, что ни одна строка не может соответствовать WHERE-оператор. Функция MIN()/MAX() вернёт NULL.
no matching row in const table Таблица была таблицей const (таблица с единственной возможной соответствующей строкой), но строка не найдена.
No tables used SELECT был подзапросом, который не использовал никакие таблицы. Например, не было FROM-оператор или FROM DUAL-оператор.
Not exists Остановка поиска после нахождения одной единственной соответствующей строки. Эта оптимизация используется с LEFT JOIN, где явно ищут строки, которые не существуют в LEFT JOIN TABLE. Пример: SELECT * FROM t1 LEFT JOIN t2 on (...) WHERE t2.not_null_column IS NULL. Поскольку t2.not_null_column может быть NULL, только если не было совпадения по условию, мы можем остановить поиск, если найдём одну соответствующую строку.
Open_frm_only Для таблиц information_schema. Для каждой соответствующей строки открывался только frm (файл определения таблицы).
Open_full_table Для таблиц information_schema. Для каждой соответствующей строки выполняется полное открытие таблицы для извлечения запрошенной информации. (Медленно)
Open_trigger_only Для таблиц information_schema. Для каждой соответствующей строки открывался только файл определения триггера.
Range checked for each record (index map: ...) Это происходит только тогда, когда не было хорошего индекса по умолчанию, но может быть какой-то индекс, который мог бы быть использован, когда мы можем рассматривать все столбцы из предыдущей таблицы как константы. Для каждой комбинации строк оптимизатор определит, какой индекс использовать (если таковой имеется) для извлечения строки из этой таблицы. Это не быстро, но быстрее, чем полное сканирование таблицы, которое является единственным другим вариантом. Карта индексов — это битовая маска, которая показывает, какие индексы рассматриваются для каждого условия строки.
Scanned 0/1/all databases Для таблиц information_schema. Показывает, сколько раз нам пришлось сканировать каталог.
Select tables optimized away Все таблицы в объединении были оптимизированы. Это происходит, когда мы используем только COUNT(*), MIN() и MAX() функции в SELECT, и мы смогли заменить все это константами.
Skip_open_table Для таблиц information_schema. Запрашиваемая таблица не нуждалась в открытии.
unique row not found Таблица была обнаружена как таблица const (таблица с единственной возможной соответствующей строкой) на этапе ранней оптимизации, но строка не найдена.
Using filesort Для решения запроса требуется сортировка файлов. Это означает дополнительную фазу, где мы сначала собираем все столбцы для сортировки, сортируем их с помощью внешней сортировки слиянием, а затем используем отсортированный набор для извлечения строк в отсортированном порядке. Если набор столбцов небольшой, мы сохраняем все столбцы в файле сортировки, чтобы не обращаться к базе данных для их повторного извлечения.
Using index Для извлечения необходимой информации из таблицы используется только индекс. Нет необходимости выполнять дополнительный поиск для извлечения фактической записи.
Using index condition Как 'Using where', но условие where передано в движок таблиц для внутренней оптимизации на уровне индекса.
Using index condition(BKA) Как 'Using index condition', но кроме того, мы используем доступ к ключам по группам для извлечения строк.
Using index for group-by Индекс используется для решения запроса GROUP BY или DISTINCT. Строки не читаются. Это очень эффективно, если в таблице много одинаковых записей индекса, так как дубликаты быстро пропускаются.
Using intersect(...) Для объединений index_merge. Показывается, какие индексы входят в пересечение.
Using join buffer Мы храним предыдущие комбинации строк в буфере строк, чтобы иметь возможность сравнить каждую строку со всеми комбинациями строк в буфере объединения за один раз.
Using sort_union(...) Для объединений index_merge. Показывается, какие индексы входят в объединение.
Using temporary Создаётся временная таблица для хранения результата. Это обычно происходит, если вы используете GROUP BY, DISTINCT или ORDER BY.
Using where Используется выражение WHERE (в дополнение к возможному поиску по ключу) для проверки, должна ли строка приниматься. Если у вас нет 'Используется where' вместе с типом соединения ALL, вы, вероятно, что-то делаете неправильно!
Using where with pushed condition Как 'Using where', но условие where передано в движок таблиц для внутренней оптимизации на уровне строки.
Using buffer Инструкция UPDATE сначала буферизует строки, а затем выполняет обновления, а не выполняет обновления на лету. Подробное объяснение см. в Использование алгоритма буферизации UPDATE.

Подробное EXPLAIN

Ключевое слово EXTENDED добавляет в вывод ещё один столбец, filtered, это процентная оценка строк таблицы, которые будут отфильтрованы условием.

Вывод EXPLAIN EXTENDED всегда генерирует предупреждение, так как он добавляет дополнительную информацию Message к последующей инструкции SHOW WARNINGS. Это включает в себя то, как SELECT запрос будет выглядеть после применения оптимизаций и правил переписывания, и как оптимизатор квалифицирует столбцы и таблицы.

Примеры

Как синоним для DESCRIBE или SHOW COLUMNS FROM:

DESCRIBE city;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| Name       | char(35) | YES  |     | NULL    |                |
| Country    | char(3)  | NO   | UNI |         |                |
| District   | char(20) | YES  | MUL |         |                |
| Population | int(11)  | YES  |     | NULL    |                |
+------------+----------+------+-----+---------+----------------+

Несколько примеров, чтобы увидеть, как EXPLAIN может определить неэффективное использование индексов:

CREATE TABLE IF NOT EXISTS `employees_example` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(30) NOT NULL,
  `last_name` varchar(40) NOT NULL,
  `position` varchar(25) NOT NULL,
  `home_address` varchar(50) NOT NULL,
  `home_phone` varchar(12) NOT NULL,
  `employee_code` varchar(25) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `employee_code` (`employee_code`),
  KEY `first_name` (`first_name`,`last_name`)
) ENGINE=Aria;

INSERT INTO `employees_example` (`first_name`, `last_name`, `position`, `home_address`, `home_phone`, `employee_code`)
  VALUES
  ('Mustapha', 'Mond', 'Chief Executive Officer', '692 Promiscuous Plaza', '326-555-3492', 'MM1'),
  ('Henry', 'Foster', 'Store Manager', '314 Savage Circle', '326-555-3847', 'HF1'),
  ('Bernard', 'Marx', 'Cashier', '1240 Ambient Avenue', '326-555-8456', 'BM1'),
  ('Lenina', 'Crowne', 'Cashier', '281 Bumblepuppy Boulevard', '328-555-2349', 'LC1'),
  ('Fanny', 'Crowne', 'Restocker', '1023 Bokanovsky Lane', '326-555-6329', 'FC1'),
  ('Helmholtz', 'Watson', 'Janitor', '944 Soma Court', '329-555-2478', 'HW1');

SHOW INDEXES FROM employees_example;
+-------------------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table             | Non_unique | Key_name      | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------------------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| employees_example |          0 | PRIMARY       |            1 | id            | A         |           7 |     NULL | NULL   |      | BTREE      |         |               |
| employees_example |          0 | employee_code |            1 | employee_code | A         |           7 |     NULL | NULL   |      | BTREE      |         |               |
| employees_example |          1 | first_name    |            1 | first_name    | A         |        NULL |     NULL | NULL   |      | BTREE      |         |               |
| employees_example |          1 | first_name    |            2 | last_name     | A         |        NULL |     NULL | NULL   |      | BTREE      |         |               |
+-------------------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

SELECT по первичному ключу:

EXPLAIN SELECT * FROM employees_example WHERE id=1;
+------+-------------+-------------------+-------+---------------+---------+---------+-------+------+-------+
| id   | select_type | table             | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+------+-------------+-------------------+-------+---------------+---------+---------+-------+------+-------+
|    1 | SIMPLE      | employees_example | const | PRIMARY       | PRIMARY | 4       | const |    1 |       |
+------+-------------+-------------------+-------+---------------+---------+---------+-------+------+-------+

Тип const, это означает, что может быть возвращён только один результат. Теперь, возвращая ту же запись, но ища по номеру телефона:

EXPLAIN SELECT * FROM employees_example WHERE home_phone='326-555-3492';
+------+-------------+-------------------+------+---------------+------+---------+------+------+-------------+
| id   | select_type | table             | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+------+-------------+-------------------+------+---------------+------+---------+------+------+-------------+
|    1 | SIMPLE      | employees_example | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where |
+------+-------------+-------------------+------+---------------+------+---------+------+------+-------------+

Здесь тип All, это значит, что ни один индекс не может быть использован. Учитывая количество строк, для извлечения записи потребовалось полное сканирование таблицы (все шесть строк). Если необходимо искать по номеру телефона, нужно создать индекс.

SHOW EXPLAIN пример:

SHOW EXPLAIN FOR 1;
+------+-------------+-------+-------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table | type  | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+-------+-------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | tbl   | index | NULL          | a    | 5       | NULL | 1000107 | Using index |
+------+-------------+-------+-------+---------------+------+---------+------+---------+-------------+
1 row in set, 1 warning (0.00 sec)

Пример оптимизации ref_or_null

SELECT * FROM table_name
  WHERE key_column=expr OR key_column IS NULL;

ref_or_null часто происходит, когда вы используете подзапросы с NOT IN, так как тогда нужно сделать дополнительную проверку на NULL значения, если первое значение не имело соответствующей строки.

См. также

  • SHOW EXPLAIN
  • Игнорируемые индексы
Содержимое, воспроизведённое на этом сайте, является собственностью соответствующих владельцев, и это содержимое не проходит предварительной проверки MariaDB. Мнения, информация и мнения, выраженные в этом содержимом, не обязательно отражают взгляды MariaDB или любой другой стороны.

© 2023 MariaDB
Licensed under the Creative Commons Attribution 3.0 Unported License and the GNU Free Documentation License.
https://mariadb.com/kb/en/explain/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API