MySql慢查优化之路|01-执行计划
保持数据的一致性,可使用事务处理;
字段固定,数据更新的成本低;
可以进行一些复杂查询。
上面展示的字段具体是什么含义,有什么意义,哪些可以作为我们设计优化参考点,我们细细来看。
2.1 id 列
用于记录唯一标识的同时,可以表明执行顺序,规则如下:
数字越大越先执行;
相等时,按照由上至下的顺序执行;
如果为null,代表一个结果集,无需使用它来查询。
2.2 select_type 列
表示查询类型,有如下:
值 | 条件 | 说明 |
---|---|---|
simple | 没有union和子查询的简单查询 |
有连接查询时,外查查询为simple(仅有一个) |
primary | 有union或子查询 | 位于最外层查询即为primary(仅有一个) |
union | uion连接查询 | 第一个查询是dervied派生表,其他都属于union |
union result | 包含union的结果集 | 在union和union all语句中,因为它不需要参与查询,所以id字段为null |
dependent union | 同union,出现在union 或union all语句中 | 会受到外部查询的影响(mysql优化器会将in优化成exists) 例:select * from bbs_topic where id in(select id from bbs_topic union select id from bbs_topic); --会转化成 -- |
subquery | 除了from包含的子查询 | 除from子句中包含子查询外,其他地方出现的子查询都可能是 |
dependent subquery | 同dependent union | 会受到外部表查询的影响 |
derived | from子句中出现的子查询(称“派生表”) | 其他数据库中可能叫做内联视图或嵌套select |
materialization | 通过将子查询结果作为一个临时表来加快查询执行速度(称“物化”) | 正常来说是常驻内存,下次查询会再次引用临时表 |
2.3 table 列
一般显示的查询表名,有别名会显示别名;
如果不涉及表数据操作,显示为null;
如果显示数据外层带尖括号,代表查询的是临时表(后面带N,代表相关id为N的查询产生的)。
2.4 type 列
访问类型,表示找到所查询数据的方法,有如下:
值 | 条件 | 说明 |
---|---|---|
system | 表的存储引擎是myisam或memory时,当表是空表或只存在一条数据 | 无需磁盘IO,速度非常快 |
const | 当查询最多匹配一行时 |
常出现于where条件是=的情况,只有=的右边是常量的时候才会走const |
eq_ref | 多表关联查询时,(第二张表)根据唯一非空索引进行查询的情况(返回必须一条) | |
ref | 多表关联查询时,根据唯一非空索引进行查询的情况 | |
fulltext | 全文索引检索 |
优先级很高,与普通索引同时存在时会优先选择全文索引(不惜代价) |
ref_or_null | 同ref,多了null值比较 | |
unique_subquery | 用于where中带in的子查询 |
子查询返回不重复且唯一 |
index_subquery | in形式子查询中用到辅助索引或常数列表 |
子查询可返回重复值,可用索引去重 |
range | 索引范围扫描 |
常见于使用>,<,is null,between ,in ,like等运算符的查询中 |
index_merge | 表示查询使用了两个以上的索引,最后取交集或者并集 |
常见and ,or的条件使用了不同的索引,官方排序这个在ref_or_null之后,但是实际上由于要读取多个索引,性能可能大部分时间都不如range |
index | 索引全表扫描,把索引从头到尾扫一遍 | 常见于使用索引列就可以处理不需要读取数据文件的查询、可以使用索引排序或者分组的查询 |
all | 全表扫描数据文件,再在server层进行过滤返回符合要求的记录 |
总结说明:
性能从好到差依次:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL;
除了all之外,其他的type都可以使用到索引;
除了index_merge之外,其他的type只可以用到一个索引;一般来说,好的sql查询至少达到range级别,最好能达到ref。
2.5 possible_keys 列
查询中可能使用到的索引。
2.6 key 列
查询真正使用到的索引。
特殊说明:
select_type为index_merge时,这里可能出现两个以上的索引;其他的select_type这里只会出现一个。
2.7 key_len 列
使用到的索引长度。
说明:
如果是多列索引,查询时不一定使用到所有的列,会计算出具体使用的长度;
只计算where条件用到的索引长度,排序和分组就算用到索引也不会计算到key_len中;
该值越小越好。
2.8 ref 列
表示连接查询的连接条件。
说明:
如果是使用的常数等值查询,这里会显示const;
如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段;
如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func。
2.9 rows 列
表示此次查询预估读取的行数。该值越小越好。
2.10 extra 列
表示解决查询的其他信息,有几十种不同的值,罗列几个常用:
值 | 条件 | 说明 |
---|---|---|
no tables used | 查询语句中不含from,或from dual 查询 | |
NULL | 询的列未被索引覆盖,并且where筛选条件是索引的前导列 | 意味着用到了索引,但是部分字段未被索引覆盖,必须通过“回表”来实现,不是纯粹地用到了索引,也不是完全没用到索引 |
using index | 查询时不需要回表查询,直接通过索引就可以获取查询的数据 | 理想中的SQL查询 |
Using where | 查询的列未被索引覆盖,where筛选条件非索引的前导列 | |
Using where Using index | 查询的列被索引覆盖,并且where筛选条件是索引列之一但是不是索引的前导列 | 意味着无法直接通过索引查找来查询到符合条件的数据 |
Using index condition | 与Using where类似,查询的列不完全被索引覆盖,where条件中是一个前导列的范围 | |
using temporary | 表示使用了临时表存储中间结果 | 临时表可以是内存临时表和磁盘临时表,执行计划中看不出来,需要查看status变量,used_tmp_table,used_tmp_disk_table才能看出来 |
using filesort | mysql 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行 | 此时mysql会根据连接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下一般也是要考虑使用索引来优化的 |
using intersect | 表示使用and的各个索引的条件时,该信息表示是从处理结果获取交集 | |
using union | 表示使用or连接各个使用索引的条件时,该信息表示从处理结果获取并集 | |
using sort_union | 用and和or查询信息量大时,先查询主键,然后进行排序合并后返回结果集 |
|
using sort_intersection | ||
firstmatch(tb_name) | 可能会在where语句含有in()类型的子查询,若内表的数据量较大时出现 | 5.6.x版本开始引入的优化子查询的新特性之一 |
loosescan(m..n) | 可能会在in()类型的子查询中,返回记录有重复时出现 | 5.6.x版本开始引入的优化子查询的新特性之一 |
2.11 filtered 列
表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例(不是具体记录数)。
5.7之后版本的默认字段,之前的版本需要使用explain extended时才会出现。
结合这些字段值,我们可以验证SQL的执行效率,也可以作为优化的切入点。