一、EXPLAIN Output Columns
Column | Json Name | Meaning | Remark |
id | select_id | 执行编号,标识select所属的行。如果在语句中没子查询或关联查询,只有唯一的select, 每行都将显示1。否则,内层的select语句一般会顺序编号,对应于其在原始语句中的位置 | |
select_type | None | 显示本行是简单或复杂select。如果查询有任何复杂的子查询,则最外层标记为PRIMARY (DERIVED、UNION、UNION RESUlT) | |
table | table_name | 访问引用哪个表(引用某个查询,如“derived3”) | |
partitions | partitions | 匹配的分区 | |
type | access_type | 数据访问/读取操作类型(ALL、index、range、ref、eq_ref、const/system、NULL) | |
possible_keys | possible_keys | 揭示哪一些索引可能有利于高效的查找 | |
key | key | 显示mysql决定采用哪个索引来优化查询 | |
key_len | key_length | 显示mysql在索引里使用的字节数 | |
ref | ref | 显示了之前的表在key列记录的索引中查找值所用的列或常量 | |
rows | rows | 为了找到所需的行而需要读取的行数,估算值,不精确。通过把所有rows列值相乘, 可粗略估算整个查询会检查的行数 | |
filtered | filtered | 按表条件过滤的行百分比 | |
Extra | None | 额外信息,如using index、filesort等 |
id(Json name: select_id)
选择标识符。这是查询中SELECT的序号。如果行引用其他行的联合结果,则该值可以为NULL。在本例中,表列显示了一个值,例如,以表示该行是指id值为M和N的行的联合。
select_type(Json name: none)
类型 | Json Name | 说明 |
SIMPLE | None | 简单子查询,不包含子查询和union |
PRIMARY | None | 包含union或者子查询,最外层的部分标记为primary |
UNION | None | 位于union中第二个及其以后的子查询被标记为union,第一个就被标记为primary如果是union位于from中则标记为derived |
DEPENDENT UNION | dependent (true) | 顾名思义,首先需要满足UNION的条件,及UNION中第二个以及后面的SELECT语句,同时该语句依赖外部的查询 |
UNION RESULT | union_result | 用来从匿名临时表里检索结果的select被标记为union result |
SUBQUERY | None | 一般子查询中的子查询被标记为subquery,也就是位于select列表中的查询 |
DEPENDENT SUBQUERY | dependent (true) | 和DEPENDENT UNION相对UNION一样 |
DERIVED | None | 派生表——该临时表是从子查询派生出来的,位于form中的子查询 |
MATERIALIZED | materialized_from_subquery | 物化子查询 |
UNCACHEABLE SUBQUERY | cacheable (false) | 无法缓存结果的子查询,并且必须为外部查询的每一行重新计算。 |
UNCACHEABLE UNION | cacheable (false) | 第二个或稍后在一个属于可缓存子查询的UNION中进行选择 |
table(Json name: table_name)
输出行引用的表的名称。这也可以是下列值之一:
:行是指id值为M和N的行的联合。
:行引用了一个id值为n的行的派生表结果,例如,从from子句的子查询中可以得到一个派生表。
:行是指一个物化子查询的结果,该子查询的id值为N.
对应行正在访问哪一个表,表名或者别名
关联优化器会为查询选择关联顺序,左侧深度优先当from中有子查询的时候,表名是derivedN的形式,N指向子查询,也就是explain结果中的下一列
当有union result的时候,表名是union 1,2等的形式,1,2表示参与union的query id
注意:MySQL对待这些表和普通表一样,但是这些“临时表”是没有任何索引的。
partitions(Json name)
由查询匹配记录的分区。对于非分区表,值为NULL。
type(Json name: access_type)
连接类型。有关不同类型的描述,请参见:type详解
possible_keys(Json name: possible_keys)
指示了MySQL可以选择的索引来查找表中的行。注意,这个列完全独立于来自EXPLAIN的输出中显示的表的顺序。这意味着,可能在使用生成的表顺序时,一些可能的键可能无法使用。
如果该列为NULL(或在json格式的输出中未定义),则没有相关索引。在这种情况下,您可以通过检查WHERE子句来检查是否引用了适合于索引的某些列或列,从而提高查询的性能。如果是这样,创建一个适当的索引并再次检查查询。
简单地说就是显示查询使用了哪些索引,表示该索引可以进行高效地查找,但是列出来的索引对于后续优化过程可能是没有用的。
key(Json name: key)
键列表示MySQL实际决定使用的键(索引)。如果MySQL决定使用一个可能的键索引来查找行,那么该索引将被列为键值。key可能会命名一个不存在于可能性键值的索引。如果所有的可能性键索引都不适合查找行,那么就会发生这种情况,但是查询所选择的所有列都是其他索引的列。也就是说,命名索引覆盖所选的列,因此,尽管它不用于确定要检索哪些行,但是索引扫描比数据行扫描更有效。
对于InnoDB,即使查询也选择主键,辅助索引也可能覆盖选定的列,因为InnoDB将主键值存储在每个次要索引中。如果key是NULL,那么MySQL没有发现用于更有效地执行查询的索引。
要强制MySQL使用或忽略在可能的键列中列出的索引,使用force索引,使用索引,或者在查询中忽略索引。
key_len(Json name: key_length)
key_len列表示MySQL决定使用的键的长度。key_len的值使您能够确定一个多部分的关键MySQL实际使用了多少部分。如果键列表示为空,len_len列也表示为空。
由于密钥存储格式,对于一个可以为空的列,密钥长度比非空列更大。
ref(Json name: ref)
ref列显示哪些列或常量与键列中命名的索引相比较,以从表中选择行。
如果值是func,则使用的值是某个函数的结果。要查看哪个函数,请在解释后使用显示警告来查看扩展的解释输出。这个函数实际上可能是一个运算符,例如算术运算符。
rows(Json name: rows)
行列表示MySQL认为必须检查执行查询的行数。
对于InnoDB表,这个数字是一个估计值,可能并不总是准确的。
filtered(Json name: filtered)
过滤后的列表示将被表条件过滤的表行的估计百分比。即行显示了估计的行数检查和行×过滤/ 100显示的行数,与以前的表。
Extra(Json name: none)
Extra是EXPLAIN输出中另外一个很重要的列,该列显示MySQL在查询过程中的一些详细信息,MySQL查询优化器执行查询的过程中对查询计划的重要补充信息。对于不同值对应的解释请参见:Extra详解
二、EXPLAIN Join Types
类型 | 描述 |
system | 该表只有一行(=系统表),这是const连接类型的一个特例。 |
const | 该表最多有一个匹配行,在查询开始时读取。因为只有一行,所以这个行中的列值可以被其他优化器视为常量。 const表非常快,因为它们只读过一次。 当将主键或惟一索引的所有部分与常量值进行比较时,将使用const。 |
eq_ref | 从该表中读取一行与前几表中的每一行的组合。除了系统和const类型之外,这是最好的连接类型。当一个索引 的所有部分都被连接使用时,它被使用,索引是一个主键或唯一的非空索引。 eq_ref可用于与使用=操作符进行比较的索引列。比较值可以是一个常量,也可以是一个表达式,它使用在表之 前读取的表中的列。 |
ref | 所有具有匹配索引值的行都从该表中读取,用于从上一个表中每一行的组合。如果联接仅使用键的最左前缀, 或者键不是主键或惟一索引(换句话说,如果联接不能基于键值选择单个行),则使用ref。如果使用的键只匹配 几行,这是一个很好的连接类型。 ref可以用于与使用=或<=>操作符进行比较的索引列。 |
fulltext | 连接是使用全文索引执行的。 |
ref_or_null | 这个连接类型就像ref,但是加上MySQL对包含空值的行进行了额外的搜索。这种连接类型优化通常用于解决子查询。 |
index_merge | 此连接类型指示使用索引合并优化。 |
unique_merge | unique_subquery只是一个索引查找函数,它完全替代了子查询以提高效率。 |
unique_subquery | 这个连接类型类似于unique_subquery。它在子查询中替换。 |
range | 只有在给定范围内的行被检索,使用索引来选择行。输出行中的键列指示使用哪个索引。key_len包含所使用的最 长密钥部分。此类型的ref列为空。 当一个键列与一个常量进行比较时,可以使用范围:=,<>,>,>=,<,<=,为NULL, <=>, BETWEEN, 或IN()操作符。 |
index | 索引连接类型与ALL相同,只是扫描索引树。发生这种情况两个方面: 如果索引是查询的覆盖索引,并且可以用来满足表所需的所有数据,那么只扫描索引树。在本例中,额外的列表示 使用索引。一个索引扫描通常比所有的都快,因为索引的大小通常小于表数据。 一个完整的表扫描使用从索引的读取来查找索引顺序中的数据行。使用索引不会出现在额外的列中。当查询仅使用单个索引的一部分的列时,MySQL可以使用此连接类型。 |
all | 最坏情况全表扫描,对上一个表中的每一行的组合都进行了完整的表扫描。通常情况下,如果表是第一个未标 记为const的表,并且在所有其他情况下通常都非常糟糕,那么这通常是不好的。通常情况下,您可以通过添加 索引来避免所有的问题,这些索引可以根据前面的表中的常量值或列值来从表中进行行检索。 |
三、EXPLAIN Extra Information
如果希望尽可能快地进行查询,请注意使用文件集和使用临时的、或在json格式的EXPLAIN输出中使用的额外列值,用于using_filesort和using_temporary_table属性等于true。
类型 | Json property | 描述 |
Child of 'table' pushed join@1 | message text | 这个表被引用为连接中的表子,可以被推到NDB内核。只有在启用推入连接时才应 用于NDB集群。 |
const row not found | const_row_not_found | 对于查询,例如SELECT…从tbl_name中,表为空。 |
Deleting all rows | message | 为了删除,一些存储引擎(例如MyISAM)支持一个处理方法,它以简单和快速的方式 删除所有表行。如果引擎使用此优化,将显示此额外值。 |
Distinct | distinct | MySQL正在寻找不同的值,因此在找到第一个匹配行之后,它停止为当前行组合搜 索更多行。 |
FirstMatch(tbl_name) | first_match | 半连接的FirstMatch连接捷径策略用于tbl_name。 |
Full scan on NULL key | message | 当优化器不能使用索引查找访问方法时,将子查询优化作为回退策略。 |
Impossible HAVING | message | HAVING子句总是错误的,不能选择任何行。 |
Impossible WHERE | message | WHERE子句总是错误的,不能选择任何行。 |
Impossible WHERE noticed after reading const tables | message | MySQL已经阅读了所有的const(和系统)表,并注意到WHERE子句总是错误的。 |
LooseScan(m..n) | message | 半连接的LooseScan策略被使用。m和n是关键的零件号。 |
No matching min/max row | message | 没有行满足查询的条件,例如SELECT MIN(…)从…条件的地方。 |
no matching row in const table | message | 对于连接的查询,有一个空的表或一个没有满足唯一索引条件的行。 |
No matching rows after partition pruning | message | 对于删除或更新,优化器在分区修剪之后没有发现任何删除或更新的内容。它在意 义上类似于不可能在哪里选择语句。 |
No tables used | message | 查询没有FROM子句,或有FROM DUAL子句。 对于插入或替换语句,请解释在没有选择部分时显示此值。例如,它出现在解释 插入到t值(10)中,因为这相当于从对偶中插入到t选择10。 |
Not exists | message | MySQL可以在查询中执行左连接优化,并且在查找与左连接标准匹配的一行之后, 不检查该表中的更多行。 |
Plan isn't ready yet | none | 当优化器还没有为在命名连接中执行的语句创建执行计划时,这个值就会发生。如果 执行计划输出包含多个行,那么它们中的任何一个或全部都可能具有这个额外的值, 这取决于优化器在确定完整执行计划时的进度。 |
Range checked for each record (index map: N) | message | MySQL没有找到使用的好索引,但是发现一些索引可能在前面的表的列值之后被使 用。对于前面的表中的每一行组合,MySQL检查是否可以使用范围或index_merge访 问方法来检索行。这不是非常快,但是比没有索引的连接要快。 |
Scanned N databases | message | 这表明在处理INFORMATION_SCHEMA表的查询时,服务器执行多少目录扫描。 |
Select tables optimized away | message | 优化器确定应该返回最多一行,而要生成这一行,必须读取一个确定的行集。当在 优化阶段(例如,通过读取索引行)读取要读的行时,在查询执行期间不需要读取任何表。 第一个条件是当查询被隐式分组(包含一个聚合函数,但不包含GROUP BY子句)时实现 的。当每个索引执行一行查找时,第二个条件就满足了。读取的索引数量决定要读取的行数。 |
Skip_open_table, Open_frm_only, Open_full_table | message | Skip_open_table:不需要打开表文件。通过扫描数据库目录,可以在查询中获得信息。 Open_frm_only:只需要打开表的.frm文件。 Open_full_table:未优化的信息查找。必须打开.frm、. myd和. myi文件。 |
Start temporary, End temporary | message | 这表明半连接重复Weedout策略的临时表使用。 |
unique row not found | message | 对于查询,例如SELECT…从tbl_name中,没有行满足表中唯一索引或主键的条件。 |
Using filesort | using_filesort | MySQL必须做一个额外的传递,以查找如何以排序的顺序检索行。排序是通过按照join类 型进行所有行,并存储排序键并将指针指向与WHERE子句匹配的所有行。然后对键进行 排序,并按排序顺序检索行。 |
Using index | using_index | 列信息是从表中检索出来的,只使用索引树中的信息,而不需要额外查找实际的行。当 查询仅使用单个索引的一部分的列时,可以使用此策略。 对于具有用户定义的聚集索引的InnoDB表,可以使用该索引,即使在额外的列中没有使 用索引时也可以使用该索引。如果类型是索引,关键是主键。 |
Using index condition | using_index_condition | 通过访问索引元组来读取表,并首先测试表,以确定是否读取完整的表行。通过这种方 式,索引信息被用来延迟(“向下推”)读取整个表行,除非它是必需的。 |
Using index for group-by | using_index_for_group_by | 与使用索引表访问方法类似,使用GROUP - BY的索引表示,MySQL发现了一个索引,该索 引可用于检索组的所有列,而不需要对实际表进行额外的磁盘访问。此外,索引以最有效的方式使用,因此每个组只读取几个索引条目。 |
Using join buffer (Block Nested Loop), Using join buffer | using_join_buffer | 来自早期连接的表被部分地读入到连接缓冲区中,然后它们的行从缓冲区中使用,以执行与当前表的连接。 (Block嵌套循环)表示使用块Nested-Loop算法和(批处理密钥访问)指示使用批处理密钥访问算法。也就是说,在EXPLAIN输出的前一行中,从表中得到的键将被缓冲,并且匹配的行将从表中以使用连接缓冲区出现的行表示的批次中获取。 在json格式的输出中,using_join_buffer的值总是要么是块嵌套循环,要么是批处理键访问。 |
Using MRR | message | 使用多范围阅读优化策略来读取表。 |
Using sort_union(...), Using union(...), Using intersect(...) | message | 这些说明了特定的算法,显示了索引扫描是如何合并到index_merge连接类型的。 |
Using temporary | using_temporary_table | 为了解决查询,MySQL需要创建一个临时表来保存结果。如果查询包含了GROUP BY和ORDER BY子句,那么通常会发生这种情况。 |
Using where | attached_condition | WHERE子句用于限制哪些行匹配下一个表或发送给客户机。除非您特别打算从表中获取或 检查所有行,否则您的查询中可能会出现错误,如果额外的值没有使用,并且表连接类型为all 或index。 在json格式的输出中没有直接对应的内容;attached_condition属性包含所使用的任何条件。 |
Using where with pushed condition | message | 此项目仅适用于NDB表。这意味着NDB集群使用条件下推优化来提高非索引列和常量之间的直接 比较的效率。在这种情况下,条件被“推下”到集群的数据节点,并同时对所有数据节点进行评估。 这就消除了在网络上发送不匹配的行的需要,并且可以在条件下推的情况下,以5到10倍的速度 加快这些查询,但是没有使用。 |
Zero limit | message | 该查询有一个LIMIT 0子句,不能选择任何行。 |