本文内容基于《高性能MySQL》第三版,宁海元、周振兴、彭立勋、翟卫祥等译。
在SELECT之前增加EXPLAIN之后,MySQL会在查询上设置一个标记。当执行查询时,这个标记会使其返回关于在执行计划中每一步的信息,而不是执行它。它会返回一行或多行信息,显示出执行计划中的每一部分和执行的次序。
1. id
这一列总是包含一个编号,标识SELECT所属的行。如果在语句中没有子查询或联合,那么只会有唯一的SELECT,于是每一行在这个列中都将显示一个1,否则,内层的SELECT语句一般会顺序编号,对应于其在原始语句中的位置。
2. select_type
这一列显示了对应行是简单还是复杂SELECT,SIMPLE意味着查询不包括子查询和UNION,如果查询有任何复杂的子部分,则最外层部分标记为PRIMARY,其他部分标记如下:
- SUBQUERY:包含在SELECT列表中的子查询中的SELECT,即不再FROM子句中;
- DERIVED:表示包含在FROM子句的子查询中的SELECT,MySQL会递归执行并将结果放到一个临时表中,服务器内部称其“派生表”,因为该临时表是从子查询中派生来的;
- UNION:在UNION中的第二个和随后的SELECT被标记为UNION,第一个SELECT被标记就好像它以部分外查询来执行,如果UNION被FROM子句中的子查询包含,那么它的第一个SELECT会被标记为DERIVED,UNION RESULT是用来从UNION的匿名临时表检索结果的SELECT。
3. table
这一列显示了对应行正在访问哪个表。在通常情况下,它就是那个表,或是该表的别名。
4. type
这一列表示关联类型或访问类型,就是MySQL决定如何查找表中的行,从最差到最优如下:
- ALL:按行全表扫描;
- index:按索引次序全表扫描,主要优点是避免了排序,如果Extra列中看到"Using index",说明MySQL正在使用覆盖索引,它只扫描索引的数据,而不是按索引次序的每一行,它比按索引次序全表扫描的开销要少很多;
- range:按索引次序范围扫描,比如BETWEEN、WHERE子句里带有">"、"<"的查询、IN()和OR;
- ref:使用非主键且非唯一索引的情况下,按照索引查找,它返回所有匹配某个单个值的行,可能会找到多个符合条件的行,所以也需要小范围扫描;
- eq_ref:使用非主键或唯一索引的情况下,多表连接的时候;
- const, system:当MySQL能对查询的某部分进行优化并将其转换成一个常量时,比如在WHERE子句中使用主键或唯一索引的列作筛选条件,MySQL就能把这个查询转换为一个常量;
- NULL:意味着MySQL能在优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引。
5. possible_keys
这一列显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的。这个列表是在优化过程的早期创建的,因此有些罗列出来的索引可能对于后续优化过程是没用的。
6. key
这一列显示了MySQL决定采用哪个索引来优化对该表的访问。如果该索引没有出现在possible_keys列中,那么MySQL选用它是处于另外的原因,例如覆盖索引。
7. key_len
这一列显示了MySQL在索引里使用的字节数。
8. ref
这一列显示了之前的表在key列记录的索引中查找值所用的列或常量。
9. rows
这一列是MySQL估计为了找到所需的行而要读取的行数。
10. Extra
这一列包含的是不适合在其他列显示的额外信息。
- Using index:表示MySQL将使用覆盖索引,以避免访问表;
- Using where:表示MySQL将在存储引擎检索行后再进行过滤,许多WHERE条件里设计索引中的列,当它读取索引时,就能被存储引擎检验,因此不是所有带WHERE子句的查询都会显示Using where,有时暗示着查询可受益于不同的索引;
- Using temporary:表示MySQL对查询结果排序时会使用一个临时表;
- Using filesort:表示MySQL会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。