{EXPLAIN | DESCRIBE | DESC}
tbl_name [col_name | wild]
{EXPLAIN | DESCRIBE | DESC}
[explain_type] [INTO variable]
{[schema_spec] explainable_stmt | FOR CONNECTION connection_id}
{EXPLAIN | DESCRIBE | DESC} ANALYZE [FORMAT = TREE] [schema_spec] select_statement
explain_type: {
FORMAT = format_name
}
format_name: {
TRADITIONAL
| JSON
| TREE
}
explainable_stmt: {
SELECT statement
| TABLE statement
| DELETE statement
| INSERT statement
| REPLACE statement
| UPDATE statement
}
schema_spec:
FOR {SCHEMA | DATABASE} schema_name
The DESCRIBE
和 EXPLAIN
语句是同义词。在实践中,DESCRIBE
关键字通常用于获取表结构信息,而 EXPLAIN
用于获取查询执行计划(即 MySQL 如何执行查询的解释)。
以下讨论使用 DESCRIBE
和 EXPLAIN
关键字根据这些用途,但 MySQL 解析器将它们视为完全同义词。
DESCRIBE
提供了表中的列信息:
mysql> DESCRIBE City;
+------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+----------------+
| Id | int(11) | NO | PRI | NULL | auto_increment |
| Name | char(35) | NO | | | |
| Country | char(3) | NO | UNI | | |
| District | char(20) | YES | MUL | | |
| Population | int(11) | NO | | 0 | |
+------------+----------+------+-----+---------+----------------+
DESCRIBE
是 SHOW COLUMNS
的快捷方式。这些语句也显示视图的信息。Section 15.7.7.6, “SHOW COLUMNS 语句” 中提供了更多关于输出列的信息。
默认情况下,DESCRIBE
显示表中的所有列信息。col_name
,如果给定,是表中的列名。在这种情况下,语句仅显示指定列的信息。wild
,如果给定,是一个模式字符串。它可以包含 SQL %
和 _
通配符。在这种情况下,语句仅显示名称与字符串匹配的列信息。无需将字符串括在引号中,除非它包含空格或其他特殊字符。
The DESCRIBE
语句是为了与 Oracle 兼容而提供的。
The SHOW CREATE TABLE
, SHOW TABLE STATUS
, and SHOW INDEX
语句也提供了表信息。见 Section 15.7.7, “SHOW 语句”。
The explain_format
系统变量对 EXPLAIN
语句的输出没有影响,当用于获取表列信息时。
The EXPLAIN
语句提供了 MySQL 执行语句的信息:
-
EXPLAIN
工作于SELECT
,DELETE
,INSERT
,REPLACE
,UPDATE
, 和TABLE
语句。 -
当
EXPLAIN
与可解释语句一起使用时,MySQL 会显示优化器关于语句执行计划的信息。也就是说,MySQL 会解释它如何处理语句,包括关于表如何连接和顺序的信息。有关使用EXPLAIN
获取执行计划信息的信息,请参阅 第 10.8.2 节,“EXPLAIN 输出格式”。 -
当
EXPLAIN
与FOR CONNECTION
一起使用,而不是与可解释语句一起使用时,它将显示命名连接中的语句执行计划。请参阅 第 10.8.4 节,“获取命名连接的执行计划信息”。connection_id
-
对于可解释语句,
EXPLAIN
生产额外的执行计划信息,可以使用SHOW WARNINGS
显示。请参阅 第 10.8.3 节,“扩展 EXPLAIN 输出格式”。 -
EXPLAIN
对于检查涉及分区表的查询非常有用。请参阅 第 26.3.5 节,“获取分区信息”。 -
FORMAT 选项可以用于选择输出格式。
TRADITIONAL
以表格格式显示输出。这是默认格式,如果没有 FORMAT 选项。JSON
格式以 JSON 格式显示信息。TREE
提供树形输出,具有比TRADITIONAL
格式更精确的查询处理描述;它是唯一显示哈希连接使用的格式(请参阅 第 10.2.1.4 节,“哈希连接优化”),并且总是用于EXPLAIN ANALYZE
。在 MySQL 8.3 中,
EXPLAIN
的默认输出格式(即没有 FORMAT 选项时)由explain_format
系统变量的值确定。该变量的确切效果将在本节后面描述。MySQL 8.3 支持使用
INTO
选项与EXPLAIN FORMAT=JSON
,使得可以将 JSON 格式的输出保存到用户变量中,如下所示:mysql> EXPLAIN FORMAT=JSON INTO @myselect -> SELECT name FROM a WHERE id = 2; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @myselect\G *************************** 1. row *************************** @myex: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "1.00" }, "table": { "table_name": "a", "access_type": "const", "possible_keys": [ "PRIMARY" ], "key": "PRIMARY", "used_key_parts": [ "id" ], "key_length": "4", "ref": [ "const" ], "rows_examined_per_scan": 1, "rows_produced_per_join": 1, "filtered": "100.00", "cost_info": { "read_cost": "0.00", "eval_cost": "0.10", "prefix_cost": "0.00", "data_read_per_join": "408" }, "used_columns": [ "id", "name" ] } } } 1 row in set (0.00 sec)
这适用于任何可解释语句(
SELECT
、TABLE
、INSERT
、UPDATE
、REPLACE
或DELETE
)。以下是使用UPDATE
和DELETE
语句的示例:mysql> EXPLAIN FORMAT=JSON INTO @myupdate -> UPDATE a SET name2 = "garcia" WHERE id = 3; Query OK, 0 rows affected (0.00 sec) mysql> EXPLAIN FORMAT=JSON INTO @mydelete -> DELETE FROM a WHERE name1 LIKE '%e%'; Query OK, 0 rows affected (0.00 sec) mysql> SELECT @myupdate, @mydelete\G *************************** 1. row *************************** @myupdate: { "query_block": { "select_id": 1, "table": { "update": true, "table_name": "a", "access_type": "range", "possible_keys": [ "PRIMARY" ], "key": "PRIMARY", "used_key_parts": [ "id" ], "key_length": "4", "ref": [ "const" ], "rows_examined_per_scan": 1, "filtered": "100.00", "attached_condition": "(`db`.`a`.`id` = 3)" } } } @mydelete: { "query_block": { "select_id": 1, "table": { "delete": true, "table_name": "a", "access_type": "ALL", "rows_examined_per_scan": 2, "filtered": "100.00", "attached_condition": "(`db`.`a`.`name1` like '%e%')" } } } 1 row in set (0.00 sec)
您可以使用 MySQL JSON 函数来处理该值,如使用
JSON_EXTRACT()
的示例:mysql> SELECT JSON_EXTRACT(@myselect, "$.query_block.table.key"); +----------------------------------------------------+ | JSON_EXTRACT(@myselect, "$.query_block.table.key") | +----------------------------------------------------+ | "PRIMARY" | +----------------------------------------------------+ 1 row in set (0.01 sec) mysql> SELECT JSON_EXTRACT(@myupdate, "$.query_block.table.access_type") AS U_acc, -> JSON_EXTRACT(@mydelete, "$.query_block.table.access_type") AS D_acc; +---------+-------+ | U_acc | D_acc | +---------+-------+ | "range" | "ALL" | +---------+-------+ 1 row in set (0.00 sec)
请参阅 第 14.17 节,“JSON 函数”。
尝试使用
INTO
子句而不明确地包括FORMAT=JSON
导致EXPLAIN
被拒绝,错误代码为ER_EXPLAIN_INTO_IMPLICIT_FORMAT_NOT_SUPPORTED
。这与当前的explain_format
系统变量的值无关。INTO
子句不支持EXPLAIN ANALYZE
;它也不支持FOR CONNECTION
。Important如果出于任何原因,语句被拒绝,用户变量将不会被更新。
-
MySQL 8.3 支持
FOR SCHEMA
子句,该子句使EXPLAIN
行为就像语句被执行在命名数据库中一样;FOR DATABASE
作为同义词被支持。一个简单的使用示例如下所示:mysql> USE b; Database changed mysql> CREATE SCHEMA s1; Query OK, 1 row affected (0.01 sec) mysql> CREATE SCHEMA s2; Query OK, 1 row affected (0.01 sec) mysql> USE s1; Database changed mysql> CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, c2 INT NOT NULL); Query OK, 0 rows affected (0.04 sec) mysql> USE s2; Database changed mysql> CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY, c2 INT NOT NULL, KEY i1 (c2)); Query OK, 0 rows affected (0.04 sec) mysql> USE b; Database changed mysql> EXPLAIN FORMAT=TREE FOR SCHEMA s1 SELECT * FROM t WHERE c2 > 50\G *************************** 1. row *************************** EXPLAIN: -> Filter: (t.c2 > 50) (cost=0.35 rows=1) -> Table scan on t (cost=0.35 rows=1) 1 row in set (0.00 sec) mysql> EXPLAIN FORMAT=TREE FOR SCHEMA s2 SELECT * FROM t WHERE c2 > 50\G *************************** 1. row *************************** EXPLAIN: -> Filter: (t.c2 > 50) (cost=0.35 rows=1) -> Covering index scan on t using i1 (cost=0.35 rows=1) 1 row in set (0.00 sec)
如果数据库不存在,语句将被拒绝,错误代码为
ER_BAD_DB_ERROR
。如果用户没有足够的权限来运行语句,它将被拒绝,错误代码为ER_DBACCESS_DENIED_ERROR
。FOR SCHEMA
不兼容FOR CONNECTION
。
EXPLAIN
需要与执行explained语句相同的权限。此外,EXPLAIN
也需要 SHOW VIEW
权限来查看任何explained视图。EXPLAIN ... FOR CONNECTION
也需要 PROCESS
权限,如果指定的连接属于不同的用户。
系统变量 explain_format
确定了 EXPLAIN
的输出格式,当用于显示查询执行计划时。该变量可以采用与 FORMAT
选项相同的值,另外还可以使用 DEFAULT
作为 TRADITIONAL
的同义词。以下示例使用了 country
表来自 world
数据库,可以从 MySQL: Other Downloads 下载:
mysql> USE world; # Make world the current database
Database changed
检查 explain_format
的值,我们看到它具有默认值,因此 EXPLAIN
(无 FORMAT
选项)使用传统的表格输出:
mysql> SELECT @@explain_format;
+------------------+
| @@explain_format |
+------------------+
| TRADITIONAL |
+------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT Name FROM country WHERE Code Like 'A%';
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | SIMPLE | country | NULL | range | PRIMARY | PRIMARY | 12 | NULL | 17 | 100.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
如果我们将 explain_format
的值设置为 TREE
,然后重新运行相同的 EXPLAIN
语句,输出将使用树形格式:
mysql> SET @@explain_format=TREE;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@explain_format;
+------------------+
| @@explain_format |
+------------------+
| TREE |
+------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT Name FROM country WHERE Code LIKE 'A%';
+--------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+--------------------------------------------------------------------------------------------------------------+
| -> Filter: (country.`Code` like 'A%') (cost=3.67 rows=17)
-> Index range scan on country using PRIMARY over ('A' <= Code <= 'A????????') (cost=3.67 rows=17) |
+--------------------------------------------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
如前所述,FORMAT
选项覆盖了该设置。执行相同的 EXPLAIN
语句,使用 FORMAT=JSON
而不是 FORMAT=TREE
,显示这是正确的:
mysql> EXPLAIN FORMAT=JSON SELECT Name FROM country WHERE Code LIKE 'A%';
+------------------------------------------------------------------------------+
| EXPLAIN |
+------------------------------------------------------------------------------+
| {
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "3.67"
},
"table": {
"table_name": "country",
"access_type": "range",
"possible_keys": [
"PRIMARY"
],
"key": "PRIMARY",
"used_key_parts": [
"Code"
],
"key_length": "12",
"rows_examined_per_scan": 17,
"rows_produced_per_join": 17,
"filtered": "100.00",
"cost_info": {
"read_cost": "1.97",
"eval_cost": "1.70",
"prefix_cost": "3.67",
"data_read_per_join": "16K"
},
"used_columns": [
"Code",
"Name"
],
"attached_condition": "(`world`.`country`.`Code` like 'A%')"
}
}
} |
+------------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
要将 EXPLAIN
的默认输出返回到表格格式,设置 explain_format
为 TRADITIONAL
。或者,您可以将其设置为 DEFAULT
,这将产生相同的效果,如下所示:
mysql> SET @@explain_format=DEFAULT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@explain_format;
+------------------+
| @@explain_format |
+------------------+
| TRADITIONAL |
+------------------+
1 row in set (0.00 sec)
MySQL 8.3 支持两种 JSON 输出格式。版本 1 是线性格式,始终用于 MySQL 8.2 及更早版本;这仍然是 MySQL 8.3 的默认值,并在本节中已经显示了示例。版本 2 的 JSON 输出格式基于访问路径,旨在与未来版本的 MySQL Optimizer 兼容。您可以通过将 explain_json_format_version
服务器系统变量的值设置为 2
来切换到版本 2 格式,如下所示:
mysql> SELECT @@explain_json_format_version;
+-------------------------------+
| @@explain_json_format_version |
+-------------------------------+
| 1 |
+-------------------------------+
1 row in set (0.00 sec)
mysql> SET @@explain_json_format_version = 2;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@explain_json_format_version;
+-------------------------------+
| @@explain_json_format_version |
+-------------------------------+
| 2 |
+-------------------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN FORMAT=JSON SELECT Name FROM country WHERE Code LIKE 'A%';
+------------------------------------------------------------------------------+
| EXPLAIN |
+------------------------------------------------------------------------------+
| {
"query": "/* select#1 */ select `world`.`country`.`Name` AS `Name` from `world`.`country` where (`world`.`country`.`Code` like 'A%')",
"inputs": [
{
"ranges": [
"('A' <= Code <= 'A????????')"
],
"covering": false,
"operation": "Index range scan on country using PRIMARY over ('A' <= Code <= 'A????????')",
"index_name": "PRIMARY",
"table_name": "country",
"access_type": "index",
"estimated_rows": 17.0,
"index_access_type": "index_range_scan",
"estimated_total_cost": 3.668778400708174
}
],
"condition": "(country.`Code` like 'A%')",
"operation": "Filter: (country.`Code` like 'A%')",
"access_type": "filter",
"estimated_rows": 17.0,
"estimated_total_cost": 3.668778400708174
} |
+------------------------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
在使用版本 2 格式后,您可以通过将 explain_json_format_version
设置回 1
(默认值)来使所有后续 EXPLAIN FORMAT=JSON
语句的 JSON 输出恢复到版本 1 格式。
值explain_json_format_version
确定了所有使用JSON输出格式的EXPLAIN
语句的版本,无论是因为给定的EXPLAIN
语句包括明确的FORMAT=JSON
选项,还是因为系统变量explain_format
被设置为JSON
。
使用EXPLAIN
,您可以看到哪里应该添加索引以使语句执行更快,使用索引来查找行。您也可以使用EXPLAIN
来检查优化器是否以最佳顺序连接表。要提示优化器使用与SELECT
语句中表的顺序相对应的连接顺序,请以SELECT STRAIGHT_JOIN
而不是SELECT
开始语句。(见第15.2.13节,“SELECT语句”。)
优化器跟踪有时可能提供与EXPLAIN
相似的信息。但是,优化器跟踪的格式和内容可能会在版本之间更改。详细信息,请参阅MySQL Internals: Tracing the Optimizer。
如果您遇到索引未被使用的问题,而您认为它们应该被使用,请运行ANALYZE TABLE
以更新表统计信息,如键的基数,这些信息可能会影响优化器的选择。见第15.7.3.1节,“ANALYZE TABLE语句”。
MySQL Workbench具有Visual Explain功能,提供了EXPLAIN
输出的可视化表示。见Tutorial: Using Explain to Improve Query Performance。
EXPLAIN ANALYZE
运行语句并生成EXPLAIN
输出,包括计时和优化器期望与实际执行之间的其他信息。对于每个迭代器,以下信息将被提供:
-
估算执行成本
(一些迭代器不在成本模型中,因此不包括在估算中。)
-
估算返回的行数
-
返回第一行的时间
-
执行该迭代器(包括子迭代器,但不包括父迭代器)的时间,以毫秒为单位。
(当有多个循环时,该数字显示每个循环的平均时间。)
-
迭代器返回的行数
-
循环次数
查询执行信息使用EXPLAIN ANALYZE
始终使用
FORMAT=TREE
指定;其他格式不受支持。
EXPLAIN ANALYZE
可以与SELECT
语句、多表UPDATE
和DELETE
语句,以及TABLE
语句一起使用。
您可以使用KILL QUERY
或CTRL-C终止该语句。
EXPLAIN ANALYZE
不能与FOR CONNECTION
一起使用。
示例输出:
mysql> EXPLAIN ANALYZE SELECT * FROM t1 JOIN t2 ON (t1.c1 = t2.c2)\G
*************************** 1. row ***************************
EXPLAIN: -> Inner hash join (t2.c2 = t1.c1) (cost=4.70 rows=6)
(actual time=0.032..0.035 rows=6 loops=1)
-> Table scan on t2 (cost=0.06 rows=6)
(actual time=0.003..0.005 rows=6 loops=1)
-> Hash
-> Table scan on t1 (cost=0.85 rows=6)
(actual time=0.018..0.022 rows=6 loops=1)
mysql> EXPLAIN ANALYZE SELECT * FROM t3 WHERE i > 8\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t3.i > 8) (cost=1.75 rows=5)
(actual time=0.019..0.021 rows=6 loops=1)
-> Table scan on t3 (cost=1.75 rows=15)
(actual time=0.017..0.019 rows=15 loops=1)
mysql> EXPLAIN ANALYZE SELECT * FROM t3 WHERE pk > 17\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t3.pk > 17) (cost=1.26 rows=5)
(actual time=0.013..0.016 rows=5 loops=1)
-> Index range scan on t3 using PRIMARY (cost=1.26 rows=5)
(actual time=0.012..0.014 rows=5 loops=1)
示例输出中的表是由以下语句创建的:
CREATE TABLE t1 (
c1 INTEGER DEFAULT NULL,
c2 INTEGER DEFAULT NULL
);
CREATE TABLE t2 (
c1 INTEGER DEFAULT NULL,
c2 INTEGER DEFAULT NULL
);
CREATE TABLE t3 (
pk INTEGER NOT NULL PRIMARY KEY,
i INTEGER DEFAULT NULL
);
该语句的输出中显示的实际时间值以毫秒为单位。
explain_format
对 EXPLAIN ANALYZE
有以下影响:
-
如果该变量的值为
TRADITIONAL
或TREE
(或同义词DEFAULT
),则EXPLAIN ANALYZE
使用TREE
格式。这确保该语句继续使用TREE
格式作为默认值,就像在引入explain_format
之前一样。 -
如果
explain_format
的值为JSON
,则EXPLAIN ANALYZE
除非指定FORMAT=TREE
,否则将返回错误。这是因为EXPLAIN ANALYZE
只支持TREE
输出格式。
我们在这里举例说明第二点,重新使用上一个示例中的最后一个 EXPLAIN ANALYZE
语句:
mysql> SET @@explain_format=JSON;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@explain_format;
+------------------+
| @@explain_format |
+------------------+
| JSON |
+------------------+
1 row in set (0.00 sec)
mysql> EXPLAIN ANALYZE SELECT * FROM t3 WHERE pk > 17\G
ERROR 1235 (42000): This version of MySQL doesn't yet support 'EXPLAIN ANALYZE with JSON format'
mysql> EXPLAIN ANALYZE FORMAT=TRADITIONAL SELECT * FROM t3 WHERE pk > 17\G
ERROR 1235 (42000): This version of MySQL doesn't yet support 'EXPLAIN ANALYZE with TRADITIONAL format'
mysql> EXPLAIN ANALYZE FORMAT=TREE SELECT * FROM t3 WHERE pk > 17\G
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t3.pk > 17) (cost=1.26 rows=5)
(actual time=0.013..0.016 rows=5 loops=1)
-> Index range scan on t3 using PRIMARY (cost=1.26 rows=5)
(actual time=0.012..0.014 rows=5 loops=1)
使用 FORMAT=TRADITIONAL
或 FORMAT=JSON
与 EXPLAIN ANALYZE
一起总是引发错误,无论 explain_format
的值如何。
在 MySQL 8.3 中,EXPLAIN ANALYZE
和 EXPLAIN FORMAT=TREE
的输出中的数字根据以下规则格式化:
-
范围在 0.001-999999.5 之间的数字以十进制数字打印。
小于 1000 的十进制数字有三个有效数字;其余的有四个、五个或六个有效数字。
-
范围在 0.001-999999.5 之外的数字以工程格式打印。例如,
1.23e+9
和934e-6
。 -
不打印尾随零。例如,我们打印
2.3
而不是2.30
,并打印1.2e+6
而不是1.20e+6
。 -
小于
1e-12
的数字打印为0
。