MySQL-EXPLAIN 注

EXPLAIN 中列的含义

  • id: 标识 SELECT 所属的行。如果在语句中没有子查询或联合,那么只会有唯一的 SELECT,于是每一行在这个列中都将显示一个 1。否则,内层 SELECT 语句一般会顺序编号,对应于其在原始语句中的位置。
  • select_type: 显示了对应行是简单还是复杂 SELECT(如果是后者,那么是三种复杂类型中的哪一种)。
    • SIMPLE:查询中不包含子查询和 UNION
    • PRIMARY:有任何复杂的子部分
    • SUBQUERY:包含在 SELECT 列表中的子查询的 SELECT(换句话说,不在 FROM 子句中)
    • DERIVED:表示包含在 FROM 子句的子查询中的 SELECT,MySQL 会递归执行并将结果放在一个临时表中。服务器内部称为『派生表』,因为该临时表是从子查询中派生来的。
    • UNION:在 UNION 中的第二个和随后的 SELECT 被标记为 UNION。第一个 SELECT 被标记就好像它以部分外查询来执行。
    • UNION RESULT:用来从 UNION 的匿名临时表检索结果的 SELECT 被标记为 UNION RESULT
  • table: 显示对应行正在访问哪个表。当 FROM 子句中有子查询或有 UNION 时,由于 MySQL 创建的匿名临时表仅在查询执行过程中存在。
    • 当在 FROM 子句中有子查询时,table 列是 <derivedN> 的形式,其中 N 是子查询的 id、这总是『向前引用』—— 换言之,N 指向 EXPLAIN 输出中后面的一行。
    • 当有 UNION 时,UNION RESULT 的 table 列包含一个参与 UNION 的 id 列表。这总是『向后引用』,因为 UNION RESULT 出现在 UNION 中所有参与行之后。
  • partitions: 代表给定表所使用的分区。
  • type: 访问类型——换言之就是 MySQL 决定如何查找表中的行。下面是最重要的访问方法,依次从最差到最优:
    • ALL:全表扫描,通常意味着 MySQL 必须扫描整张表,从头到尾,去找到需要的行。(例外是使用了 LIMIT 或者在 Extra 列中显示 “Using distinct/not exists”)
    • index: 这个跟全表扫描一样,只是 MySQL 扫描表时按索引次序进行而不是行。它的主要优点是避免了排序;最大的缺点是要承担按索引次序读取整个表的开销。这通常意味着若是按随机次序访问行,开销将会非常大。如果在 Extra 列中看到 “Using index”,说明 MySQL 正在使用覆盖索引,它只扫描索引的数据,而不是按索引次序的每一行。它比按索引次序全表扫描的开销要少很多。
    • range: 范围扫描就是一个有限制的索引扫描,它开始于索引里的某一点,返回匹配这个值域的行。它比全索引扫描好一些,因为它用不着遍历全部索引。显而易见的范围扫描是带有 BETWEEN 或在 WHERE 子句中带有 > 的查询。当 MySQL 使用索引去查找一系列值时,例如 IN()OR 列表,也会显示为范围扫描。然而,这两者其实是相当不同的访问类型,在性能上有重要的差异。具体可查看 《高性能 MySQL》 第五章文章『什么是范围条件』。
    • ref:这是一种索引访问(有时也叫做索引查找),它返回所有匹配某个单个值的行。然而,它有可能会找到多个符合条件的行,因此,它是查找和扫描的混合体。此类索引访问只有当使用非唯一性索引或者唯一性索引的非唯一性前缀时才会发生。把它叫做 ref 是因为索引要跟某个参考值相比较。ref_or_null 是 ref 智商的一个变体,它意味着 MySQL 必须在初次查找的结果里进行第二次查找以找出 NULL 条目。
    • eq_ref:使用这种所有查找,MySQL 知道最多只返回一条符合条件的查询。这种访问方法可以在 MySQL 使用主键或者唯一性索引查找时看到,它会将它们与某个参考值做比较。
    • const, system:当 MySQL 能对查询的某部分进行优化并将其转换成一个常量时,它就会使用这些访问类型。举例来说,如果你通过将某一行的主键放入 WHERE 子句里的方式来选取此行的主键,MySQL 就能把这个查询转换为一个常量。然后就可以高效地将表从联接执行中移除。
    • NULL:这种访问方式意味着 MySQL 能在优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引。例如,从一个索引列里选取最小值可以通过单独查找索引来完成,不需要再执行时访问表。
  • possible_keys: 显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的。这个列表是在优化过程的早起创建的,因此有些罗列出来的索引可能对于后续优化过程是没用的。
  • key: 显示了 MySQL 决定采用哪个索引来优化对该表的访问。如果该索引没有出现在 possible_keys 列中,那么 MySQL 选用它是出于另外的原因——例如,它可能选择了一个覆盖所有,哪怕没有 WHERE 子句。换句话说, possible_keys 揭示了哪一个索引能有助于高效地行查找,而 key 显示的是优化采用哪一个索引可以最小化查询成本。
  • key_len: MySQL 在索引里使用的字节数。
  • ref: 显示了之前表在 key 列记录的索引中查找值所用的列或常量。
  • rows: MySQL 估计为了找到所需的行而要读取的行数。
  • filtered: 针对表里符合某个条件(WHERE 子句或联接条件)的记录数的百分比所做的一个悲观估计。
  • Extra: 包含的是不适用在其他列显示的额外信息。常见的最重要的值如下:
    • Using index:使用了覆盖索引。
    • Using where:MySQL 服务器将在存储引擎检索行后再进行过滤。许多 WHERE 条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带 WHERE 子句的查询都会显示 “Using where” 。有时 “Using where” 的出现就是一个暗示:查询可受益于不同的索引。
    • Using temporary:意味着 MySQL 在对查询结果排序时会使用一个临时表。
    • Using filesort:这意味着 MySQL 会在结果使用一个外部索引排序,而不是按索引次序从表里读取行。MySQL 有两种文件排序算法,两种方式都可以在内存或磁盘上完成。EXPLAIN 不会告诉你 MySQL 将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
    • Range checked for each record (index map: N):这个值以为着没有好用的索引,新的索引将在联接的每一行上重新估计。N 是显示在 possible_keys 列中索引的位图,并且是冗余的。