SQL优化

对于SQL优化,首先要思考如下问题:
SQL语句如何进行优化;SQL语句如何查看执行计划,关注哪些优化因素。

执行计划概览
SQL优化

id 每个被独立执行的操作标识,标识对象被操作的顺序,id值越大,先被执行,如果相同,执行顺序从上到下
select_type 查询中每个select 字句的类型
table 被操作的对象名称,通常是表名,但有其他格式
partitions 匹配的分区信息(对于非分区表值为NULL)
type 连接操作的类型
possible_keys 可能用到的索引
key 优化器实际使用的索引
key_len 被优化器选定的索引键长度,单位是字节
ref 表示本行被操作对象的参照对象,无参照对象为NULL
rows 查询执行所扫描的元组个数(对于innodb,此值为估计值)
filtered 条件表上数据被过滤的元组个数百分比
extra 执行计划的重要补充信息

可在mysql client 中输入 help explain 查看explain的帮助命令和语法,常用的用法是 explain extended(输出更多扩展信息)和explain format=json (json格式输出,可看到cost等信息)

========================
SQL优化步骤
第一步 查看执行计划:
在SQL前加上 explain extended,主要关注select_type(查询类型)、key(用到什么索引)、rows(查询执行扫描的元组个数)、extra(是否利用到排序、临时表等)。
由图可知:app_apply_step 表未用到索引,进行了全表扫描,app_mst和app_profile 两表利用了主键索引。
SQL优化
第二步 查看SQL涉及的表结构,此处主要查看app_apply_step 表:
show create table app_apply_step\G, 主要关注表的索引和where 条件中的字段类型。
可见 app_apply_step 表 is_exp 字段上无索引,且为tinyint类型。
SQL优化
第三步 思考可能优化的点:
看出索引区分度
先查看表 app_apply_step 字段某个字段is_exp的索引区分度 。
执行 select count()/(select count() from app_apply_step) from app_apply_step where is_exp =0 ; 如下图所示
is_exp 字段区分度约等于0,表明通过索引筛选非常高效。
执行建索引操作:
alter table app_apply_step add index idx_is_exp (is_exp);
SQL优化
第四步 重新执行SQL和查看执行计划:
执行计划用到了新建的索引,且执行时间从0.54秒到0.00秒(时间被四舍五入)。

SQL优化

总结SQL优化步骤
1. 查看执行计划 explain extended (数据库工具,命令行窗口)
2. 如果有告警信息,查看告警信息 show warnings;(命令行窗口)
3. 查看SQL涉及的表结构和索引信息
4. 根据执行计划,思考可能的优化点
5. 按照可能的优化点执行表结构变更、增加索引、SQL改写等操作
6. 查看优化后的执行时间和执行计划
7. 如果优化效果不明显,重复第四步操作

SQL优化常见问题

慢SQL常见问题 解决办法
`where条件中索引列用!=(不等于) 和 not in 例如: select * from tb where a != 3` `select * from tb where a > 3 and a < 3`
索引列函数转换,索引列参与计算 例如:select * from tb where a +3= 5; select * from tb where date(a) = ‘2018-03-23’; 索引列不参与计算和函数转换select * from tb where a = 5 - 3;select * from tb where a = date(‘20180323 14:00:00’);
字段类型隐式转换,例如a字段为varchar字符型, select * from tb where a = test; where条件字段类型保持一致 select * from tb where a = ‘test’;
`表结构和索引设计不合理,复合索引中未使用前导列 例如:a、b、c为符合索引,select * from tb where b = 1 and c = 2;` 索引尽量使用复合索引,并使用前导列,索引个数一般不超过5个 select * from tb where b = 1 and c = 2(将符合索引修改为b、c、a);
like/regexp %匹配符在左边 例如:select * from tb where a like ‘%test%’; 符合业务逻辑,修改为:select * from tb where a like ‘test%’;
大数据量分页问题,M>=10000, 例如:select * from tb limit M,N 改成基于主键查询,SELECT * FROM tb WHERE ID > =(select ID from tb limit M, 1) limit N

感谢公司MBA关于SQL优化的讲解