执行计划
使用 EXPLAIN 关键字可以模拟优化器执行 SQL 语句,并分析查询语句的性能瓶颈。
一、环境准备¶
1. 创建表¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
2. 插入数据¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
二、Explain 结果列¶
1. id¶
id字段是select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。id情况有三种
1.1 id相同¶
执行顺序从上到下
1 2 3 4 5 6 7 8 9 | |
1.2 id不同¶
id值越大,优先级越高,越先被执行。
1 2 3 4 5 6 7 8 9 | |
1.3 id有相同也有不同¶
id相同的可以认为是一组,从上往下顺序执行;在所有的组中,id的值越大,优先级越高,越先执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
2. select_type¶
表示SELECT的类型,常见的取值,如下表所示:
| select_type | 含义 |
|---|---|
SIMPLE |
简单的SELECT查询,查询中不包含子查询或者UNION |
PRIMARY |
查询中若包含任何复杂的子查询,最外层查询标记为PRIMARY |
SUBQUERY |
在SELECT或 WHERE列表中包含了子查询 |
DERIVED |
在FROM列表中包含的子查询,被标记为 DERIVED(衍生)。MYSQL会递归执行这些子查询,把结果放在临时表中 |
UNION |
若第二个SELECT出现在UNION之后,则标记为UNION; 若 UNION包含在FROM子句的子查询中,外层SELECT将被标记为 : DERIVED |
UNION RESULT |
从UNION的匿名临时表获取结果的SELECT |
3. table¶
对应行查询的表。
- 当
from子句中有子查询时,table 列为是<derivenN>的格式,表示这一行的执行的是id = N行的查询。 - 当有
union时,table 的数据为<union M,N>的格式,M和N表示参与union的select行id。
4. partitions¶
查询将与记录相匹配的分区。对于非分区表,该值为 NULL。
5. type¶
type 显示的是访问类型,是较为重要的一个指标,可取值为:
| type | 含义 |
|---|---|
NULL |
MySQL不访问任何表、索引,直接返回结果 |
system |
表只有一行记录(等于系统表),这是const类型的特例,一般不会出现 |
const |
表示通过索引一次就找到了,const用于比较primary key或者 unique 索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,MySQL 就能将该查询转换为一个常量。 |
eq_ref |
当主键或唯一键索引的相关列并联接使用时(联表查询),最多匹配一条符合条件的记录。这是除了 const之外的最好的联接类型,简单的 select 查询不会出现 req_ref,更多出现在联表查询。 |
ref |
本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体。此类索引访问只有当使用非唯一性索引或者唯一性索引的非唯一性前缀时才会发生。把它叫做ref是因为索引要跟某个参考值相比较,这个参考值是一个常数或者是来自多表查询前一个表里的结果值。 |
range |
范围扫描,通常出现在 between、>、<等操作中,使用一个索引来检索给定范围的行。 |
index |
index 与 ALL的区别为: index类型只是遍历了索引树, 通常比ALL快, ALL是遍历数据文件。 |
ALL |
全表扫描,扫描主键(聚簇、聚集)索引树的所有叶子节点,通常这种情况下要根据业务场景来增加其他索引进行优化。(例外:查询中使用了LIMIT、或者在Extra列中显示“Using distinct/not exists”)。 |
结果值从最好到最坏依次是:
1 | |
一般来说, 我们需要保证查询至少达到range级别, 最好达到ref 。
其他可能出现字段:
1 | |
6.possible_keys¶
possible_keys 主要显示查询可能用到哪些索引来查找,只是可能会使用,并不代表一定会使用。
常见值说明:
NULL: 没有相关索引,如果是 NULL 的话,可以考虑在 where 子句中创建一个适当的索引来提高查询性能,然后继续用 explain 查看其效果;也有可能出现 possible_keys 为 NULL,但是 key 有值,实际走了索引。 有列值:如果显示表中的某列,则表示可能会走这一列对应列值的索引;如果 possible_keys 有值,但是 key 显示 NULL,这种情况一般存在于表中数据量不大的情况,因为 MySQL 语句优化器认为索引对此查询的帮助不大,从而选择了全表查询。
7. key¶
key 表示 MySQL 实际采用哪个索引来优化对该表的查询。
如果没有使用索引,则该列为 NULL。
查询中若使用了覆盖做引,则该索引仅出现在key列表中。
8. key_len¶
显示了 MySQL 索引所使用的字节数,通过这个数值可以计算具体使用了索引中的哪些列(主要用于联合索引的优化)。
如果字段允许设置为
NULL,则需要1字节来记录是否为NULL;Not NULL的列则不需要。
9. ref¶
显示了之前的表在key列记录的索引中查找值所用的列或常量
10. row¶
显示预计查询的结果数,并不是真正的结果集中的记录(行)数,仅供参考。
11filtered¶
查询的结果行数(记录)占总读取行数(记录)的百分比,最大为 100 (也就是 100%),意味着没有对行进行筛选。
12.extra¶
其他的额外的执行计划信息,在该列展示 。
Using index:使用覆盖索引,在 type 相同的情况下, Extra 的值为 Using index 要比为 NULL 性能高。 表示相应的SELECT操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错!如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
Using where:使用 where 关键字来查询,并且对应的列没有设置索引,对应的 key 为 NULL。
Using index condition:非覆盖索引查询并进行了回表,并且辅助索引使用了条件查询语句(where 或其他)。
Using temporary:MySQL 需要创建创建一个临时表来处理查询,出现这种情况一般要添加索引进行优化处理。 常见于排序order by和分组查询group by。
Using filesort:使用外部排序而不是索引排序,当数据较小的时候采用的是内存排序,当数据量较大的时候会频繁的访问磁盘,并将排序后的数据写入磁盘。
Select tables optimized away:使用聚合函数(例如 max、min等)来访问存在索引的字段时,只访问索引树中已排好序的叶子,节点性能很高。
八、执行计划¶
1. 获取执行计划¶
1 2 3 4 5 6 7 | |
2. 关键字段¶
2.1 table查询的表¶
2.2 type 查询的类型:全表,索引¶
type字段可能出现的值
2.2.1 ALL 全表扫描,不走索引¶
例1:查询条件列没有索引
1 | |
例2:查询条件出现以下语句(辅助索引)
1 2 3 4 5 6 7 8 9 10 | |
2.2.2 INDEX 全索引¶
1 2 3 4 5 6 7 8 9 10 | |
2.2.3 RANGE 索引范围扫描¶
- 辅助索引:>、 >=、 <、 <= 、LIKE、 IN、 OR
- 主键:<>、 NOT IN
例:
1 2 3 4 5 6 7 | |
注意:
2.2.4 ref 非唯一性索引,等值查询¶
1 2 3 4 5 6 7 8 9 10 11 | |
2.2.5 eq_ref 在多表连接时,连接条件使用了唯一索引¶
1 2 3 4 5 6 7 8 9 10 11 | |
2.2.6 system,const 唯一索引的等值查询¶
1 2 3 4 5 6 7 | |
2.3 possible_keys 可能会用到的索引¶
2.4 key 使用到的索引,判断索引是否合理¶
2.5 extra 额外信息¶
2.5.1 filesort 文件排序¶
说明在SQL语句中存在排序
1 2 3 4 5 6 7 | |
1 2 3 4 5 6 7 8 9 10 11 | |
当看到执行计划extra位置出现filesort,说明有文件排序出现
观察需要排序(ORDER BY,GROUP BY,DISTINCT)的条件有没有索引
根据子句的指向顺序去创建联合索引