Skip to content

Latest commit

 

History

History
157 lines (98 loc) · 6.88 KB

04.EXPLAIN.md

File metadata and controls

157 lines (98 loc) · 6.88 KB

Explain 中的列

id 列

标识 SELECT 所在行,如果在语句当中没有子查询或联合,那么只会有唯一的SELECT,于是每一行在这个列中都将显示一个1.

SELECT 列

这一列显示了对应行是简单还是复杂 SELECT (如果是后者,那么是三种复杂类型中的哪一种)。SIMPLE 值以为着查询不包括子查询和 UNION。如果查询有任何复杂的子部分,则最外层表标记为 PRIMARY,其它部分标记如下:

SUBQUERY

包含在 SELECT 列表中的子查询中的 SELECT (换句话说,不在FROM子句中)标记为 SUBQUERY.

ERIVED

DERIVED 值用来 表示包含在 FROM 子句的子查询中的 SELECT,MySQL 会递归执行并将结果放到一个临时表中,服务器内部称其“派生表”,因为该临时表是从子查询派生来的。

UNION

在 UNION 中的第二个和随后的 SELECT 被标记为 UNION。第一个 SELECT 被标记就就好像它以部分外查询来执行。之就是之前的例子中在 UNION 中的第一个 SELECT 显示为 PRIMARY 的原因。 如果 UNION 被 FROM 子句中的子查询包含,那么它的第一个 SELECT 会被表产为 DERIVED。

UNION RESULT 用来从 UNION 的匿名临时表检索结果的 SELECT 被标记为 UNION RESULT。

table 列

这一列显示了对应行正在访问哪个表。

派生表与联合

当 FROM 子句中有子查询或有UNION时,table列会变得复杂很多。在这些场景下,确实没有一个“表”可以参考到,因为MySQL创建的匿名表仅在查询执行过程中存在。

当在 FROM 子句中有子查询时,table 列是 <derivedN> 的形式,其中 N 是子查询的 id。这总是“向前引用” —— 换言之,N 指向 EXPLAIN 输出中后面的一行。

示例:

EXPLAIN
SELECT actor_id,
       (SELECT 1 FROM sakila.film_actor WHERE film_actor.actor_id =
                                              der_1.actor_id LIMIT 1)
FROM (
     SELECT actor_id
    FROM sakila.actor limit 5
         ) AS der_1
UNION ALL
SELECT film_id,
       (SELECT @var1 FROM sakila.rental LIMIT 1)
FROM (
     SELECT film_id,
            (SELECT 1 FROM sakila.store LIMIT 1)
    FROM sakila.film LIMIT 5
         ) AS der_2;

type 列

这一列显示了“访问类型” —— MySQL 如何查找表中的行。

ALL

全表扫描。

index

这个跟全表扫描一样,只是 MySQL 扫描表时按索引次序排序进行而不是行。 它的主要优点是避免了排序,缺点是按索引次序读取整个表(容易过程按随机次序访问行,开销将非常大)。

如果在 Extra 列中看到“Using index”,说明 MySQL 正在使用覆盖索引,它只扫描索引的数据,而不是按索引次序的每一行。它比按索引次序全表扫描开销要少很多。

range

范围扫描返回匹配某个索引范围的行。它就是一个有限制的索引扫描。它比全索引扫描好一点,不用遍历全部索引。

ref

这是一种索引访问,它返回匹配某个单值的行。这种访问只有当使用非唯一索引或唯一索引的非唯一前缀时才会发生。

eq_ref

读取本表中和关联表表中的每行组合成的一行。除 了 system 和 const 类型之外, 这是最好的联接类型。这种访问方法可以在 MySQL 使用主键或者唯一性索引查找时看到。使用这种索引查找,MySQL 知道最多只返回一条符合条件的记录。

const, system

当 MySQL 能对查询的某部分进行优化并将器转换成一个常量时,它就会使用这些访问类型。比如,如果你通过将某一行的主键放入 WHERE 子句里的方式来选取此行的主键,MySQL 就能把这个查询转换为一个常量。然后就可以高效地将表从联接执行中移除。

null

这种访问方式意味着 MySQL 能在优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引。例如,从一个索引列里选择最小值可以通过单独查找索引来完成,不需要在执行时访问表。

示例:

# all
DESC SELECT * from actor;

# index
DESC SELECT last_name from actor;

# index
DESC SELECT actor_id,film_id FROM film_actor;

# range
DESC SELECT * FROM actor WHERE actor_id > 2;

# const
desc SELECT * from actor WHERE actor_id = 1;

# ref
desc SELECT actor_id FROM actor WHERE last_name = 'AKROYD';

# eq_ref
DESC SELECT a.actor_id FROM film INNER JOIN film_actor fa ON film.film_id = fa.film_id
INNER JOIN actor a ON fa.actor_id = a.actor_id;

possible_keys 列

这一列显示了查询可以使用哪些索引,这是基于查询访问的列和使用的比较操作符来判断的。这个列表是在优化过程的早期创建的,因此有些罗列出来的索引可能对于后续优化过程是没用的。

key 列

显示了 MySQL 决定采用哪个索引来优化对该表的访问。如果索引没有出现在 possible_keys 列中,那么 MySQL 选用它是出于另外的原因 —— 例如,它可能选择了一个覆盖索引,哪怕没有 WHERE 子句。

换句话说,possible_keys 揭示了哪一个索引能有助于高效地进行查找,而 keys 显示的是优化采用哪一个索引可以最小化查询成本。

key_len 列

该列显示了 MySQL 在索引里使用的字节数。如果 MySQL 正在使用只是索引里的某些列,那么就可以用这个值来算出具体是哪些列。注意,当我们计算列的使用情况时,务必把字符列中的字符集也考虑进去。

key_len 列显示了在索引字段中可能的最大长度,而不是表中数据使用的实际字节数。

ref 列

这一列显示了之前的表在 key 列记录的索引中查找值所用的列(比如索引列)或常量(比如条件值)。

rows 列

这一列是 MySQL 估计为了找到所需的行而要读取的行数。这个数字是内嵌循环关联计划里的循环数目。也就是说它不是 MySQL 认为它最终要从表里读取出来行数,而是 MySQL 为了找到符合查询的每一点上标准的那些行而必须读取的行的平均数。(这个标准包括 SQL 里给定的条件,以及来自联接次序上前一个表的当前列。

通过把所有 rows 列的值相乘,可以粗略地估算出整个查询会检查的行数。

filtered 列

在使用 EXPLAIN EXTENDED 时出现。

extra 列

"Using index" 表示 MySQL 将使用覆盖索引,以避免访问表。

"Using where" 这意味着 MySQL 服务器将在存储引擎检索行后再进行过滤。许多 WHERE 条件里涉及索引的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带 WHERE 子句的查询都会显示 "Using where"。

"Using temporary" 这意味着 MySQL 在对查询结果排序时会使用一个临时表。

"Using filesort" 这意味着 MySQL 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。