mysql查询优化整理

基于索引层面

1,覆盖索引 实际上SELECT要查询的数据都已经包含在索引中了(不 论是要查询的列,还是查询的WHERE条件),这样查询可以不再在走表,减少查询数据的次数

2,索引下推 比如where 条件为 deptno like 'A%' and empno like 'B%' ,且当前有一个联合索引为(deptno,empno),那么索引的执行会有两种方式
1)根据deptno查找所有符合条件的记录,根据mysql的二级索引需要回表查询回相应行的方式回到取表所有的记录,再根据empno的查询要求检索出相应的记录
2)根据deptno查找所有符合条件的记录,不回表直接从符合的结果再选出符合empno查询要求的记录,再回表读取出数据。
mysql默认使用索引下推,目的在于减少回表查询记录的条数

3,最左前缀 当前创建联合索引(deptno,empno)
数据库中有记录分别为deptno,empno=[{10,11},{10,12},{11,21},{12,22},{30,31},{30,32}] 那么当where 条件写成 where deptno like '1%' and empno like '2%' 的时候。最左前缀的deptno条件会先取到满足条件的记录范围,再在这个范围内读取查询相应的记录。这个功能点要和MYSQL索引的B+树结构联系。

B+树结构中各最终叶节点前有前后顺序关联,这个关联特性有利于最左前缀的展开

4,不要在where条件中对某列进行进行函数计算 ,比如 where f(x)=y(z)+20 .因为对索引的利用相当于是去直接匹配索引中所保存的值进行对比比较。一旦引入的函数计算,就意味着要对每个索引值都进行一次计算后才能确定是否符合条件

5,索引尽量包括group by ,order by 字句对应的列。 因为group by 与 order by 都会涉及到结果集的排序操作。尤其当相应的结果集较大且SQL密集时会触发临时表空局内的大规模排序操作 比如在执行计划中的extra列中可以见到 file sorts提示 这种提示就意味着可能出现了排序操作,甚至会导致因SQL查询出现数据库连接中断的情况。在group by ,order by 对应的列上增加索引,利用索引的天然排序性减少或消除在列表空间中的排序操作。既减低SQL结果反馈的时间,又减轻对临时表空间需求的压力

6,对于删除了大量数据或者插入数据的表,可以使用OPTIMIZE TABLE的操作来重新对innodb表的主键进行物理层面上的调整

基于SQL书写的
1,尽量用UNION ALL 而不是UNION
UNION ALL 是简单的返回结果集相加,不存在去重操作。而UNION 看起来简单,反倒在结果集合并时进行了去重操作,对于不需要去重的查询结果集,这等于多做了无谓操作,降低SQL效率

2,能用EXISTS尽量不用IN,能用表关联尽量不用子查询。

IN 只用于有确定有限个参数值时使用比如 IN ('36','23','38') ,而且尽量不要过百

IN EXISTS 和表关联,大概来说都是各种形式的表关联。当用了IN和EXISTS等在于在语境上告诉SQL解析器你必须要这种形式做表关联,那么SQL解析器将无法发挥调优的作用。也就是说IN和EXISTS最好的执行情况其实也和表关联时SQL解析器分析出的一般结果差不多,不会比它好多少。至于IN和EXISTS间就不做区别说明了

基于慢查询日志定位慢查询SQL根据执行计划进行调优

在查询慢SQL之前首先要定义一个合理的慢查询SQL阈值,比如先定义2秒查询返回的查询是慢查询。当先把这些慢查询清理后再逐步压低阈值,比如到300ms,再到100ms,分期分批,由紧至缓逐步推进

在检索出来的慢查询SQL中主要关注一下几个指标
1,QUERY_TIME 最直观的查询时长

2,ROWS_EXAMINED 检索了多少条记录 如果where条件或者表联接定义的不好,那么对这个值的影响就会比较大

3,ROWS_SEND 结果集记录的数量,如果查询返回1W条,速度肯定是比查询返回1条要慢

查询出慢SQL以后将相应的SQL对应的执行计划打印出来,观察执行计划的情况,有的放矢地进行调整

EXPLAIN select ………… 通过这种方式获取相应的执行计划

执行计划中会包括 id,select_type,table,type,possible_keys,key,ken_len,ref,rows,extra等列

其中id列是一组数字,其表示的是这个SQL语句中每个SQL单元执行的顺序,当序号不同时大序号的单元先执行,小序号的单元后执行。当序号相同时排在上边序号的单元先执行,下边的后执行

比如 id 返回为

1,
2,
3,
3,
4,
5,
那执行的顺序为 5,4,3(第3行) ,3(第4行),2,1

根据这个顺序去逐一观察整个SQL的执行步骤

select_type列代表每个子句的类型,是比较简单的还是比较复杂的

simple 是最简单的,没有子查询也没有union, 最普通的where条件执行的结果

primary 说明有复杂的子部分,它的最外边会被标记为primary

subquery SQL中包含子查询(可以关注是否可以性能调整)

DERIVED 衍生 本人理解为 一大段SQL的结果我把它当成表来使用比如
select from a ,(select from b) c 这里边的(select * from b) 会触发DERIVED 、

UNION 大SQL中存在对UNION 或者UNION ALL的使用,可以关注是否有性能调整点

type列的取值范围有all,index,range,ref,eq_ref,const,system null

all 全表扫描 一般来说在需要调优的复杂SQL中all的必须要调整掉,如果必要可以增加相应的查询条件,避免这种全表扫描

index 也是一种全表扫描,只是它是遍历整个索引,而不是整个表

range:索引的范围扫描,比如 deptno > 10 and deptno <30

ref:非惟一性索引扫描 比如对emp表写SQL select * from emp where depnto = '2'
这里的deptno 就是非惟一型索引列

eq_ref:惟一型索引列 比如对emp表写SQL select * from emp where empno = '2'

const,system 当表里只有一行的时候会有这种提示,到这个程度一般是不需要优化的

null:不访问表也不访问索引

通过执行计划调优主要就是看这两个列的情况,尽量减少最糟执行的出现

另外rows列也需要关注

rows列的数值很大但是执行很快的SQL,往往会是某个我们在本地测试毫无压力但是到服务器上却导致业务变满的根本原因

本地很快是因为这种SQL在本地跑时由于硬件资源许可所以速度很快。但在服务器上大量相同语句并发时可能会对系统的IO,BUFFER等资源造成争用,导致性能急剧下降

extra列中主要需要关注是否有 files sort 或者 using temporary 如果有这种提示。那说明SQL会在临表空间做排序,这个对SQL的查询速度影响很大,同时也对临表空间的压力很大。如果存在问题考虑增加临表空间,同时看看是否需要对排序或者group by 的列增加索引

另外还有基于DB参数的调整,以后整理

猜你喜欢

转载自blog.51cto.com/4890631/2484203
今日推荐