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'. - Заменить столбцы другими столбцами, имеющими идентичные значения: Пример:
WHEREa=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 значения, если первое значение не имело соответствующей строки.
См. также
© 2023 MariaDB
Licensed under the Creative Commons Attribution 3.0 Unported License and the GNU Free Documentation License.
https://mariadb.com/kb/en/explain/