MySQL优化(4):explain分析
Explain是Mysql的自带查询优化器,负责select语句的优化器模块,可以模拟优化器执行SQL查询语句,从而知道Mysql是如何处理SQL的,语法也很简单:Explain + SQL
以下是通过explain查询出的几个属性
(常见性能瓶颈 ——
CPU:CPU饱和一般发生在数据装入内存或从磁盘上读取数据时
IO:磁盘I/O瓶颈发生在装入数据远大于内存容量时
服务器硬件的性能瓶颈:top,free,iostat,vmstat来查看系统的性能状态)
用途:
(1)表的读取顺序,id
(2)数据读取操作的操作类型,select_type
(3)哪些索引可以使用
(4)哪些索引被实际使用
(5)表之间的引用
(6)每张表有多少行被优化器查询 rows
1、id:反映的是表的读取的顺序,或查询中执行select子句的顺序。
小表永远驱动大表,三种情况:
(1)id相同,执行顺序是由上至下的
(2)id不同,如果是子查询,id序号会递增,id值越大优先级越高,越先被执行
(3)id存在相同的,也存在不同的,所有组中,id越大越先执行,如果id相同的,从上往下顺序执行
derived是衍生虚表的意思,derived2中的2对应id2
2、select_type:反映的是Mysql理解的查询类型
(1)simple:简单的select查询,查询中不包含子查询或union。
(2)primary:查询中若包含任何复杂的字部分,最外层查询标记为primary。
(3)subquery:select或where列表中的子查询。
(4)derived(衍生):在from列表中包含的子查询,Mysql会递归执行这些子查询,把结果放在临时表里。
(5)union:若第二个select出现在union后,则被标记为union,若union包含在from字句的子查询中,外层select将被标记为derived
(6)union result:union后的结果集
3、table:反映这一行数据是关于哪张表的
4、type:访问类型排序
反映sql优化的状态,至少达到range级别,最好能达到ref
查询效率:system > const > eq_ref > ref > range > index > all
(完整的排序:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index >all)
(1)system:从单表只查出一行记录(等于系统表),这是const类型的特例,一般不会出现
(2)const:查询条件用到了常量,通过索引一次就找到,常在使用primary key或unique索引中出现。
where id=1写死,所以类型是const
(3)eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描。
(4)ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它可能会找到多个符合条件的行,与eq_ref的差别是eq_ref只匹配了一条记录。
(5)range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般是在where语句中出现了between、<、>、in等的查询。
这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。与eq_ref和ref的区别在于筛选条件不是固定值,是范围。
(6)index:full Index scan,index和all的区别为index类型只遍历索引树。这通常比all快,因为索引文件通常比数据文件小。
要获得的id信息,刚好id在索引上,从索引中读取
(all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
(7)all:全表扫描,如果查询数据量很大时,全表扫描效率是很低的。
5、possible_keys、key、key_len:反映实际用到了哪个索引,索引是否失效
(1)possible_keys:Mysql推测可能用到的索引有哪些,但不一定被查询实际使用
(2)key:实际使用的索引,若为null,则可能没建索引或索引失效。
(查询中若使用了覆盖索引,则该索引仅出现在key列表中。
覆盖索引:select后面的字段和所建索引的个数、顺序一致)
(3)key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。同样的查询结果下,长度越短越好。
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
6、ref:反映哪些列或常量被用于查找索引列上的值
7、rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数
仅通过主键索引查找是641行
建完相关的复合索引再查,需要查询的行数就变少了
8、Extra
(1)using filesort:mysql中无法利用索引完成的排序,这时会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
创建索引时就会对数据先进行排序,出现using filesort一般是因为order by后的条件导致索引失效,最好进行优化。
order by的排序最好和所建索引的顺序和个数一致
(2)using temporary:使用了临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。
影响更大,所以要么不建索引,要么group by的顺序要和索引一致
(3)using index:表示相应的select操作中使用了覆盖索引,避免访问了表的数据行,效率好
覆盖索引:select后的数据列只从索引就能取得,不必读取数据行,且与所建索引的个数(查询列小于等于索引个数)、顺序一致。
所以如果要用覆盖索引,就要注意select的列只取需要用到的列,不用select *,同时如果将所有字段一起做索引会导致索引文件过大,性能会下降。
出现using where,表明索引被用来执行索引键值的查找
如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
(4)using where:表明使用了where过滤
(5)using join buffer:使用了连接缓存
(6)impossible where:where子句的值是false
(7)select tables optimized away
(8)distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作