MySQL EXPLAIN 一: 输出格式详解

时间:2022-09-24 00:17:31

本文详细介绍 MySQL 数据库的 EXPLAIN 语句,旨在帮助 MySQL 开发人员更好的通过 EXPLAIN 语句分析 Sql 语句的执行计划。如有不正之处,欢迎批评指正。

为了保证内容的权威性,我选择了翻译 Mysql5.7 官方文档8.8.2 EXPLAIN Output Format 章节的内容。

英文地址:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

翻译内容如下:

8.8.2 EXPLAIN 数据格式

EXPLAIN 语句提供关于 MySQL 执行语句的信息。它同 SELECT、DELETE、INSERT、REPLACE、UPDATE语句一起使用,如:EXPLAIN SELECT * FROM TABLE。

EXPLAIN 为 SELECT 语句中使用到的每个表返回一行信息。它在输出中按照MySQL在处理语句时读取它们的顺序列出这些表。MySQL 使用 nested-loop join 解析所有的连接(joins)。这意味着 MySQL 从第一个表中读取一行记录,然后在第二个表、第三个表查找匹配行,以此类推。当所有的表被处理完成后, MySQL 输出选中的列,并且通过表数据(the table list)回溯有更多匹配行的表。从这个表中读取下一行数据,继续通过后续表进行行匹配。

EXPLAIN 语句的输出包括分区信息。同时,EXPLAIN 语句为 SELECT 语句生成扩展信息,并且随着 EXPLAIN 的SHOW WARNINGS 一起显示(见8.8.3 Extended EXPLAIN Output Format)。

注意

在旧的 MySQL 版本中,分区和扩展信息是通过 EXPLAIN PARTITIONSEXPLAIN EXTENDED 语句生成的。为了向后的兼容性,这些语法还有可以使用的,但是现在分区和扩展信息的输出在默认情况下是启用的,所以 PARTITIONS 和 EXTENDED 关键词是多余的、不被推荐的。使用它们会导致一个警告,并且在 MySQL 将来的发行版本中,它们将要被从 EXPLAIN 语法中移除。


注意

MySQL Workbench 有一个可视化的解释能力,它为 EXPLAIN 语句的输出提供一个可视化的表现。见Tutorial: Using Visual Explain to Improve Query Performance

EXPLAIN 输出列

这个章节描述 EXPLAIN 语句生成的输出列。之后的章节提供 type 和 Extra 列的附加信息。

EXPLAIN 语句的每个输出行都提供了一个表的信息。在 Table 8.1“EXPLAIN Output Columns”中总结了输出行包含的值,并加以详细的说明。表(Table 8.1)的第一列显示列名,第二列提供了等效的 JSON 属性名称,在输出格式为 JSON 时使用。

Table 8.1 EXPLAIN Output Columns

Column JSON Name 含义
id select_id select 标识符
select_type None select 类型
table table_name 输出行描述的表的表名
partitions partitions 匹配的分区
type access_type 连接类型
possible_keys possible_keys 可供选择使用的索引
key key 实际使用的索引
key_len key_length 实际使用的索引的长度
ref ref 与索引进行比较的列,也就是关联表使用的列
rows rows 将要被检查的估算的行数
filtered filtered 被表条件过滤的行数的百分比
Extra None 附件信息


注意

如果 JSON 属性的值为 NULL ,在 JSON-formatted 格式的 EXPLAIN 输出中将不被显示。

  • id (JSON name: select_id)
    SELECT 标识符,该值为 SELECT 在查询中的顺序号,如果当前行引用的是其他行的联合查询结果,该值将被设置为 NULL。在这种情况下,表中的列将显示一个类似于<union M,N>的值,标识该行为 id 值为 M 和 N 的联合。

  • select_type (JSON name: none)
    SELECT 的类型,它可以是下表中展示的任意一个值。如果该值为 SIMPLE 或者 PRIMARY,一个 JSON 格式的 EXPLAIN 将以一个 query_block 的属性显示 SELECT 的类型。JSON 的名称如下表所示。

select_type Value JSON Name 含义
SIMPLE None 简单的 SELECT (没有使用 UNION 或者 subqueries)
PRIMARY None 最外层的 SELECT
UNION None 在 UNION 查询中的第二个或者之后的 SELECT 语句
DEPENDENT UNION dependent (true) 在 UNION 查询中的第二个或者之后的 SELECT 语句,依赖外层的查询
UNION RESULT union_result 联合查询的结果
SUBQUERY None 在子查询中的第一个 SELECT
DEPENDENT SUBQUERY dependent (true) 在 subquery (子查询)中的第一个 SELECT,依赖于外层查询
DERIVED None 衍生的表 SELECT(由 FROM 中的 subquery 引起)
MATERIALIZED materialized_from_subquery 物化子查询
UNCACHEABLE SUBQUERY cacheable (false) 子查询的结果不能被缓存,必须重新评估外部查询的每一行
UNCACHEABLE UNION cacheable (false) 在 UNION(联合查询)中的第二个或者之后的多个 select 都属于不可缓存的子查询(见 UNCACHEABLE SUBQUERY)



依赖通常意味着一个相关子查询的使用。见Section 13.2.10.7, “Correlated Subqueries”

相关子查询的评估不同于不可缓存的子查询评估。关于相关子查询,子查询只重新评估一次外部上下文环境的每一组变量的不同值。关于不可缓存的子查询,子查询重新评估外部上下文环境的每一行数据。

子查询的缓存不同与 query cache 中查询结果的缓存(见 Section 8.10.3.1, “How the Query Cache Operates”)。子查询缓存发生在查询执行期间,而 query cache 用来存储查询执行完成后的结果。

当你为 EXPLAIN 指定了 JSON 格式,它的输出中没有单一的属性直接等同于 select_type,query_block 属性对应一个给定的 SELECT。它的属性等同于大多数的 SELECT 子查询类型,并且只显示可用的(例如 materialized_from_subquery),并在适当的时候进行显示。JSON 属性中没有与 SIMPLE 或者 PRIMARY等同的属性。

对于 non-SELECT 语句,select_type 显示受影响的表的语句的类型。例如:对于 DELETE 语句,select_type 的值为 DELETE。

  • table (JSON name: table_name)
    输出的行所指向的表的名称,可以是下列值之一:
    • <union M,N>:该行指的是 ID 值为 M 和 N 的行的联合。
    • <derived N>:该行指的是衍生表结果,该结果为 ID 值为 N 的行。可能会生成一个衍生表,例如:在 FROM 语句中存在一个 from a subquery。
    • <subqueryN>:该行指的是一个物化子查询的结果,该结果为 ID 值为 N 的行。见Section 8.2.2.2, “Optimizing Subqueries with Materialization”
  • partitions (JSON name: partitions)
    分区的记录将被查询匹配。对于非分区表,该值为 NULL。见Section 22.3.5, “Obtaining Information About Partitions”
  • type (JSON name: access_type)
    连接类型。不同类型的描述见EXPLAIN Join Types
  • possible_keys (JSON name: possible_keys)
    MySQL 可以选择 possible_keys 列指示的索引查找表中的行数据。注意,possible_keys 列完全独立于 EXPLAIN 输出中显示的表的顺序。这意味着 possible_keys 列中的一些 key 可能无法使用在实践中生成的表的顺序。
    如果该列的值是 NULL(或未定义JSON格式输出),说明表里没有相关的索引。在这种情况下,您可以通过检查 WHERE 子句来检查其是否引用一些列或合适的包含索引的列,从而提高查询的性能。如果是这样的话,创建一个和适当的索引并且通过 EXPLAIN 再次检查查询语句,见 Section 13.1.8, “ALTER TABLE Syntax”
    使用 SHOW INDEX FROM tbl_name 语句查看表(tbl_name )中已有的索引。
  • key (JSON name: key)
    key 列表明 MySQL 实际决定使用的索引。如果 MySQL 决定通过 possible_keys 中的某个索引查找行,那个索引被列在 key 列中。
    key 可以命名一个不包含在 possible_keys 列中的索引。这可能发生在 possible_keys 中没有为查询行数据找到合适的索引,但是所有被查询选择的列可能包含其他的索引列。也就是说,命名的索引覆盖了选中的列,因此尽管它不用于确定要检索的行,但是索引扫描比数据行扫描更有效。
    关于 InnoDB存储引擎,即使要查询一个主键,次要索引可能会 cover (覆盖)选中的列,这是因为 InnoDB 使用每个次要索引存储主键值。如果 key 值为 NULL,表明 MySQL 没有找到执行高效查询的索引。
    可以在你的查询语句中使用 FORCE INDEX、USE INDEX、IGNORE INDEX,强制 MySQL 使用或者忽略 possible_keys 列中的索引。见 Section 8.9.4, “Index Hints”
    关于 MyISAM 存储引擎,运行 ANALYZE TABLE 帮助优化器选择更好的索引。myisamchk –analyze 可以做到与 ANALYZE TABLE 一样的效果。见 Section 13.7.2.1, “ANALYZE TABLE Syntax”
  • key_len (JSON name: key_length) 和 Section 7.6, “MyISAM Table Maintenance and Crash Recovery”
    key_len 列指示 MySQL 决定使用的 key 的长度。key_len 值能够使你判定 MySQL 实际使用了 multiple-part key 中的多少个 part。如果 key 列的值为 NULL,则 key_len 列值也为 NULL。
  • ref (JSON name: ref)
    ref 列显示列或常量,这些列或者常量与 key 列中的索引进行比较,以便从表中选择行。
    如果 ref 的值为 func,那么这个值通常是一些函数执行的结果。如果想要确定是哪个函数,在 EXPLAIN 的后面增加 SHOW WARNINGS 语句可以查看扩展的 EXPLAIN 输出。该函数实际上可能是一个算术运算符。
  • rows (JSON name: rows)
    这个 rows 就是MySQL 认为在执行查询是必须进行逐行检查的行的数据量。
    对于 InnoDB 类型的表,这个数字只是一个估计,并不总是精确的。
  • filtered (JSON name: filtered)
    这个 filtered 就是一个估算的将要被表的查询条件过滤的 rows 的百分比。rows 显示估算的被检查的行的数量, rows × filtered / 100 显示将要与前一个表进行连接的行数。
  • Extra (JSON name: none)
    这列包含关于 MySQL 如何解析查询语句的附加信息。该列的不同值的描述见 EXPLAIN Extra Information
    这里没有单独的 JSON 属性与 Extra 列的值进行对应;然而,本列中可能出现的值作为 JSON 属性公开,或作为 message 属性的文本公开。

本节的内容先翻译到这里,关于连接类型、扩展信息、输出解释三部分,会在后续三篇博客中进行翻译。