MySQL性能分析之Explain

一、性能分析

1.1 MySQL Query Optimizer

1. Mysql中有专门负责优化select语句的优化器模块

主要功能:

通过计算分析系统中收集到的统计信息,为客户端请求的Query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)

2.当客户端向MySQL请求一条Query,命令解析器模块完成请求分类,区别出是select并转发给MySQL Query Optimizer时,MySQL Query Optimizer首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。

并对Query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。然后分析Query中的 Hint 信息(如果有),看显示Hint信息是否可以完全确定该Query 的执行计划。

如果没有Hint或Hint信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,然后再得出最后的执行计划

1.2 MySQL常见瓶颈

CPU:CPU在饱和的时候,一般发生在数据装入内存,或从磁盘上读取数据的时候。

IO:磁盘IO瓶颈,发生在装入的数据远大于内存容量的时候。

服务器硬件的性能瓶颈:top、free、iostat和vmstat来查看系统的性能状态。

二、Explain

2.1 是什么

使用Explain关键字可以模拟优化器执行SQL 查询语句,从而知道MySQL 是如何处理你的SQL 语句的。分析你的查询语句或是表结构的性能瓶颈

2.2 能干嘛

1.表的读取顺序

2.数据读取操作的类型

3.哪些索引理论上可以使用

4.哪些索引实际上被使用

5.表之间的引用

6.每张表有多少行被优化器查询

2.3 怎么使用

用法:

Explain+SQL语句

Explain 执行后返回的信息:

三、字段解析

id type key rows extra

3.1 id

select 查询的序列号,包含一组数字,表示查询中执行select 子句或操作表的顺序。

1.id相同,执行顺序由上而下

2.id不同,如果是子查询,id序列号会递增,序号越大,执行的优先级越高,越先被执行

类比,括号里面的先被执行。

3.id有相同也有不同,先执行序号大的,相同序号的由上而下依次执行。

id如果相同,可以认为是一组,从上往下顺序执行;

在所有组中,id值越大,优先级越高,越先执行。

衍生 = Derived

关注点:id号每个号码,表示一趟独立的查询。一个sql的查询趟数越少越好

3.2 select_type

select_type代表查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询。

3.2.1 有哪些

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
dependent subquery在select或where列表中包含了子查询,子查询基于外层
uncacheable subquery无法使用缓存的子查询

3.2.2 simple

简单的select 查询,查询中不包含子查询或者union

simple代表单表查询

3.2.3 primary

查询中若包含任何复杂的子部分,最外层查询则被标记为primary

3.2.4 derived

在from列表中包含的子查询被标记为derived(衍生),MySQL 会递归执行这些子查询, 把结果放在临时表里。

3.2.5 subquery

在select或where列表中包含了子查询

3.2.6 union

若第二个select出现在union之后,则被标记为union;若union包含在from子句的子查询中,外层select将被标记为:derived

3.2.7 union result

从union表获取结果的select

3.2.8 dependent subquery

在select或where列表中包含了子查询,子查询基于外层

都是where 后面的条件,subquery 是单个值,dependent subquery 是一组值

3.2.9 uncacheable subquery

无法使用缓存的子查询

当使用了@@来引用系统变量的时候,不会使用缓存

3.3 table

这个数据是基于哪张表的。

3.4 type

type显示的是访问类型。是较为重要的一个指标,结果值从最好到最坏依次是

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

system > const > eq_ref > ref > range > index > all

一般来说,得保证查询至少达到range 级别,最好能达到ref

3.4.1 system

表只有一行记录(等于系统表),这是const 类型的特列,平时不会出现,这个也可以忽略不计

select * from t1 where id  = 1单表且一行记录,即system

3.4.2 const

id = 1 常量

表示通过索引一次就找到了,const 用于比较primary key 或者unique 索引。因为只匹配一行数据,所以很快如将主键置于where 列表中,MySQL 就能将该查询转换为一个常量。

3.4.3 eq_ref

唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描

3.4.4 ref

非唯一性索引扫描,返回匹配某个单独值的所有行.本质上也是一种索引访问,它返回所有匹配某个单独值的行,

然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。

3.4.5 range

检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引一般就是在你的where 语句中出现了between、<、>、in 等的查询这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束语另一点,不用扫描全部索引。

3.4.6 index

出现index是sql使用了索引但是没有通过索引进行过滤,一般是使用了覆盖索引或者是利用索引进行了排序分组

Full Index Scan

index与all的区别为:index类型只遍历索引树,这通常比all类型快。因为索引文件比数据文件小。

也就是说index与all都是扫描全表,但是,index类型从索引中扫描,而all类型从磁盘中扫描。

3.4.7 all

Full Table Scan,将遍历全表以找到匹配的行。

3.4.8 index_merge

在查询过程中需要多个索引组合使用,通常出现在有or 的关键字的sql 中

3.4.9 ref_or_null

对于某个字段既需要关联条件,也需要null 值得情况下。查询优化器会选择用ref_or_null 连接查询。

3.4.10 index_subquery

利用索引来关联子查询,不再全表扫描。

3.4.11 unique_subquery

该联接类型类似于index_subquery。子查询中的唯一索引

一般来说,至少保证达到range级别,最好能达到ref

3.5 possible_keys

显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用

3.6 key

实际使用的索引。如果为null,则没有使用索引。

覆盖索引,possible_keys为null,key用到了覆盖索引,查询的字段,可以通过辅助索引找到,不再需要回表查主键索引,找到所有行数据

3.7 key_len

表示索引中使用的字节数,可通过该列计算出查询中所使用的索引长度。在不损失精度的情况下,索引越短越好

key_len 字段能够帮你检查是否充分的利用上了索引。ken_len 越长,说明索引使用的越充分。

key_len显示的值为索引字段的最大可能长度,并非实际长度。因为key_len是根据表定义计算而得,而不是通过表内检索出的

3.8 ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。

dept.deptno匹配emp的deptno,emp的ename匹配了一个常量,即‘AvDEjl'

查询中与其它表关联的字段,外键关系建立索引

3.9 rows

rows列显示MySQL认为它执行查询时必须检查的行数。越少越好

根据表统计信息以及索引的选用情况,大致估算出找到所需记录一共需要读取的行数。

3.10 extra

其他的额外重要的信息。

3.10.1 using filesort

说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取mysql中无法利用索引完成的排序操作,称为文件排序。

出现filesort的情况:

优化后,不再出现filesort 的情况

3.10.2 using temporary

使用了临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。

优化前:

优化后

3.10.3 using index

using index表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错!

如果同时出现using where,表明索引被用来执行索引键值的查找

如果没有同时出现using where,表明索引只是用来读取数据而非利用索引执行查找

利用索引进行了排序或分组。

注意:
如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。

3.10.4 using join buffer

使用了连接缓存

3.10.5 impossible where

where子句的值总是false,条件永远不成立,不能用来获取任何元组。

3.10.6 select tables optimized away

在没有GROUPBY 子句的情况下,基于索引优化MIN/MAX 操作或者对于MyISAM 存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。

在innodb中:

在myisam中:

3.10.7 distinct

优化distinct操作,在找到第一次匹配的元组后,立即停止找相同值的动作。

四、热身Case

视频教程

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值