1、引言
公司有个需求,统计短信系统每天status没成功的电话号码,然后进行统计分析。为了省事,我直接用了现成的sql, 该sql是分页,每次筛选limit一百条,最后合并下,最后不就得出所有的手机号了吗?
select id from smss where type='0' and status='0' and ctime >= '2020-03-03 00:00:00' and ctime<= '2020-03-03 23:59:59' order by id desc limit 1800,100
由于这个表是个日志表,相当大,大约有十几亿条数据,翻页是很慢的,及时有ctime限制而且有索引,大约执行了几十秒,后续优化了一把。
2、第一次优化
我想优化方案是
1、取出今天的minid
2、 where id > minid order by id asc limt 100
3、取出上一步筛选出来最大的maxid, minid= maxid再次进入2循环取,直到取不到值为止
问题的关键在于minid开始初值我写的0,为0的话minid条件不命中,条件第二次才会有。造成的慢sql
select id, mobile from sms where type='0' and status='0' and ctime >= '2020-03-04 00:00:00' and ctime<= '2020-03-04 23:59:59' order by id asc limit 100
这条sql的原因在于:ctime这个索引根本不起作用,直接用id进行扫描的,所以执行非常慢。
3、第二次优化
1、minid = select min(id) from sms where type='0' and status='0' and ctime >= '2020-03-04 00:00:00' and ctime<= '2020-03-04 23:59:59' 这个执行很快,ctime有索引
2、select id, mobile from sms where id>minid and type='0' and status='0' and ctime >= '2020-03-04 00:00:00' and ctime<= '2020-03-04 23:59:59' order by id asc limit 100
3、从2中结果取出mobiles放在内存中,同时取出这一批次中最大的maxid, minid = maxid
再次循环2取数据,直到取不到为止,这个就顺利解决了
4、总结
对于大翻页,排序按照区间的最大id为条件,再去请求数据,这样能减少扫描的行数,从而减少sql执行时间。