SQL慢查询优化

排队B端慢查询问题排查

表现:

3月19日,3月20日的18:00-20:00之间,DB服务器的CPU load飙升

DBA提出问题原因是sql

update ykct.tb_queue_applyset state=? where rest_id=? and state=? and id<=? and valid=? and apply_time>?

扫描行数太多,执行时间过长

业务场景:

tb_queue_apply表的作用是存储线上取号、取消请求,用户线上取号时会创建一条记录。

在B端心跳连接时,会传"queue_marker"参数,含义为上次处理的最后一条请求的id;

服务端收到消息,会把此商户在apply表中 id <= queue_marker 的两天内的记录标记为已处理,然后查询 id > queue_marker 的未处理记录返回给B端处理

问题分析:

1.表结构分析

tb_queue_apply表结构如下,除了主键的聚集索引之外,分别在rest_id和apply_time这两列上有单列索引

2.执行计划分析

可以看到执行计划是对主键索引和rest_id索引做了index merge,由于我们的条件是id <= 3065099,那么如果走主键索引的话,扫描索引行数会很多

3.优化策略

根据上面的分析,如果sql走的索引是rest_id或apply_time的单列索引,则索引扫描行数会少很多(因为一个商户或者两天内的线上取号量不会很多)

比较好的办法是删除rest_id列的单列索引,新建rest_id和apply_time的联合索引,这样我们的sql中如果同时有rest_id和apply_time两个条件,就一定会走这个联合索引

思考:

1.这个问题是从3月19日开始暴露出来的, 但是从监控上看这条sql在之前都没有过慢查询。所以应该是19日之前mysql优化器对于这条sql使用了rest_id和apply_time两个单列索引;但是在19日tb_queue_apply表的数据量达到某个数值之后,mysql优化器判断使用rest_id和id两个索引做index_merge更优,从而引发了慢查询。

但是即使是对rest_id和apply_time两个单列索引index_merge,其效率也不如直接使用rest_id和apply_time的联合索引。因为index_merge是对两个索引的查询结果取交集或并集,而联合索引则是先根据rest_id定位范围,然后再根据apply_time进一步缩小范围。

2.从业务场景上来看可以把sql拆为两条,先根据rest_id和apply_time确定id的下限,然后根据rest_id和id的范围做更新:

select id from ykct.tb_queue_apply where rest_id = 106503 and apply_time > '2016-03-17' order by id limit 1;

update ykct.tb_queue_apply set state = 1 where rest_id = 106503 and id between 3064288 and 3065099 and state = 0 and valid = 1;

总结:

1.创建索引:

  第一:经常做查询,连接条件为group by ,order by且区分度较高的的列

  第二:经常更新,区分度太低的列,不能作为索引

  第三:创建;联合索引,注意排序(最左前缀)

2.复杂SQL,先做explain分析计划,查看是否有效利用现在的索引,如果没有则调整索引。

3.出现慢查询找原因:第一:现根据业务场景角度入手,根据业务逻辑优化SQL执行条件(增删改查语句修改)。第二:已经没有优化再考虑SQL调整索引

你可能感兴趣的:(数据库)