EXPLAIN 语句提供有关MySQL执行语句的信息,每个表返回一行信息。处理语句时,读取它们的顺序列出输出中的表
执行EXPLAIN 语句会打印出下列内容
id, select_type, table, partitions, type, possible_keys, key , key_len, ref, rows, filtered, Extra
一、id
记录标识符
二、select_type
值 | 说明 |
SIMPLE | 简单SELECT(不使用 UNION或子查询) |
PRIMARY | 最外层SELECT |
UNION | 中的第二个或以后SELECT的语句 UNION |
DEPENDENT UNION | a 中的第二个或后面SELECT的语句 UNION,取决于外部查询 |
UNION RESULT | 的结果UNION。 |
SUBQUERY | 首先SELECT在子查询中 |
DEPENDENT SUBQUERY | 首先SELECT在子查询中,依赖于外部查询 |
DERIVED | 派生表 |
DEPENDENT DERIVED | 派生表依赖于另一个表 |
MATERIALIZED | |
UNCACHEABLE SUBQUERY | 一个子查询,其结果无法缓存,必须为外部查询的每一行重新计算 |
UNCACHEABLE UNION | UNION 属于不可缓存子查询 |
三、table
输出行所引用的表的名称
四、partitions
匹配记录属于的分区
五、type
联接类型
值 | 说明 |
system | 该表只有一行(= 系统表)。const这是连接类型 的一个特例。 |
const | 该表最多有一个匹配行,在查询开始时读取。因为只有一行,所以这一行中列的值可以被优化器的其余部分视为常量。 const表非常快,因为它们只被读取一次。 |
eq_ref | 对于先前表中的每个行组合,从该表中读取一行。除了system和const类型,这是最好的连接类型。当连接使用索引的所有部分并且索引是 a PRIMARY KEY或UNIQUE NOT NULL索引时使用它。 |
ref | 对于先前表中的每个行组合,从该表中读取具有匹配索引值的所有行。ref如果连接仅使用键的最左前缀或键不是PRIMARY KEY或 UNIQUE索引(换句话说,如果连接不能基于键值选择单行),则使用。如果使用的键只匹配几行,这是一个很好的连接类型。可用于使用 =or<=> 运算符比较的索引列 |
fulltext | 连接是使用FULLTEXT 索引执行的。 |
ref_or_null | 这种连接类型类似于ref,但另外MySQL会额外搜索包含NULL值的行。这种连接类型优化最常用于解析子查询。 |
index_merge | 此连接类型表明使用了索引合并优化。在这种情况下,key输出行中的列包含所用索引的列表,并key_len包含所用索引的最长键部分的列表。 |
unique_subquery | 只是一个索引查找功能,完全替代子查询以提高效率。 |
index_subquery | 此连接类型类似于unique_subquery. 它替换IN子查询,但它适用于子查询中的非唯一索引 |
range | 仅检索给定范围内的行,使用索引选择行。输出行中的key列指示使用了哪个索引。key_len包含使用的最长的关键部分。该ref列适用 NULL于这种类型。可以在使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN()运算符中 |
index | 连接类型与index相同ALL,只是扫描了索引树。这有两种方式:1.如果索引是查询的覆盖索引并且可以用于满足表中所需的所有数据,则仅扫描索引树。在这种情况下,该Extra列 显示Using index。仅索引扫描通常比仅索引扫描更快, ALL因为索引的大小通常小于表数据;2.使用从索引中读取以按索引顺序查找数据行来执行全表扫描。 Uses index没有出现在 Extra列中; |
当查询仅使用属于单个索引的列时,MySQL 可以使用此连接类型。 | |
ALL | 对先前表中的每个行组合进行全表扫描。如果该表是第一个未标记的表,这通常不好,并且在所有其他情况下const通常 非常糟糕。通常可以 ALL通过添加索引来避免基于先前表中的常量值或列值从表中检索行。 |
六、possible_keys
匹配行中可供选择的索引
七、key
匹配行中实际选择的索引
八、key_len
使用的密钥的长度
九、ref
该ref列显示将哪些列或常量与列中指定的索引进行比较以 key从表中选择行。
十、rows
执行的行数。对于InnoDB可能并不总是准确的。
十一、filtered
百分比,单位是%,按表条件过滤的条数和表的总条数百分比
rows × filtered = 该表与下表连接的行数
十二、Extra
附加信息
值 | 说明 |
Backward index scan | 优化器能够对 InnoDB表使用降序索引。与 一起显示 Using index。 |
Child of ‘table’ pushed join@1 | 该表被引用为table可以下推到 NDB 内核的连接中的子项。仅在启用下推连接时适用于NDB Cluster。 |
const row not found | 对于查询,表是空的。 |
Deleting all rows | |
Distinct | |
FirstMatch | 连接快捷策略 |
Full scan on NULL key | 当优化器无法使用索引查找访问方法时,子查询优化会发生这种情况作为回退策略。 |
Impossible HAVING | HAVING子句始终为 false,不能选择任何行。 |
Impossible WHERE | WHERE子句始终为 false,不能选择任何行。 |
Impossible WHERE noticed after reading const tables | MySQL已读取所有const( system) 表并注意到该WHERE子句始终为false。 |
LooseScan(m…n) | 使用半连接 LooseScan 策略。 m并且 n是关键部件号。 |
No matching min/max row | 没有行满足查询的条件 |
no matching row in const table | 对于带有连接的查询,有一个空表或没有满足唯一索引条件的行的表。 |
No matching rows after partition pruning | 对于DELETE、UPDATE,优化器在分区修剪后没有发现要删除或更新的内容 |
No tables used | 查询没有FROM子句,或有 FROM DUAL子句。 |
Not exists | MySQL 能够对LEFT JOIN 查询进行优化,并且在找到与条件匹配的行后,不会检查该表中的前一行组合的更多行LEFT JOIN |
Plan isn’t ready yet | 当优化器尚未完成为在命名连接中执行的语句创建执行计划时, 会出现此值。如果执行计划输出包含多行,则任何或所有行都可能具有此 Extra值,具体取决于优化器在确定完整执行计划时的进度。 |
Range checked for each record | MySQL 没有找到可以使用的好的索引,但发现某些索引可能会在之前表中的列值已知后使用。对于前面表格中的每个行组合,MySQL 检查是否可以使用range、index_merge访问方法来检索行。这不是很快,但比执行完全没有索引的连接要快。 |
Recursive | 该行适用于 SELECT递归公用表表达式的递归部分 |
Rematerialize | |
Scanned N databases | 处理表查询时服务器执行了多少目录扫描 INFORMATION_SCHEMA。N可以是 0、1 或 all。 |
Select tables optimized away | |
Skip_open_table, Open_frm_only, Open_full_table | Skip_open_table: 表格文件不需要打开。该信息已从数据字典中获得。Open_frm_only:表信息只需要读取数据字典。Open_full_table: 未优化的信息查找。表信息必须从数据字典中读取并通过读取表文件。 |
Start temporary, End temporary | 临时表用于 semijoin Duplicate Weedout 策略 |
unique row not found | 对于查询,没有行满足索引或表的条件 |
Using filesort | MySQL 必须做一个额外的过程来找出如何按排序顺序检索行。排序是通过根据连接类型遍历所有行并存储排序键和指向与WHERE子句匹配的所有行的行的指针来完成的。然后对键进行排序,并按排序顺序检索行 |
Using index | 仅使用索引树中的信息从表中检索列信息,而无需执行额外的查找来读取实际行。当查询仅使用属于单个索引的列时,可以使用此策略。 |
Using index condition | 通过访问索引元组并首先对其进行测试以确定是否读取完整的表行来读取表。这样,除非有必要,否则索引信息用于延迟( “下推” )读取全表行 |
Using index for group-by | 与Using index表访问方法类似,Using index for group-by 表明 MySQL 找到了一个索引,该索引可用于检索GROUP BY或 DISTINCT查询的所有列,而无需对实际表进行任何额外的磁盘访问。 |
Using index for skip scan | 跳过扫描访问方法 |
Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access), Using join buffer (hash join) | 来自早期连接的表被部分读入连接缓冲区,然后从缓冲区中使用它们的行来执行与当前表的连接。 (Block Nested Loop)指示使用块嵌套循环算法,(Batched Key Access)指示使用批量密钥访问算法,并(hash join)指示使用散列连接。也就是说, EXPLAIN输出前一行的表中的键被缓冲,匹配的行从出现的行所代表的表中批量提取 Using join buffer。 |
Using MRR | 多范围读取优化策略读取表 |
Using sort_union(…), Using union(…), Using intersect(…) | index_merge这些指示显示如何为连接类型 合并索引扫描的特定算法 |
Using temporary | 为了解析查询,如果查询包含GROUP BY和ORDER BY子句,需要创建一个临时表来保存结果。 |
Using where | |
Using where with pushed condition | 意味着 NDB Cluster 正在使用 Condition Pushdown 优化来提高非索引列和常量之间直接比较的效率。在这种情况下,条件被“下推”到集群的数据节点,并同时在所有数据节点上进行评估。这消除了通过网络发送不匹配行的需要,并且可以将此类查询速度提高 5 到 10 倍,比可以使用但不使用条件下推的情况。 |
Zero limit | 该查询有一个LIMIT 0子句,不能选择任何行。 |