1.问题
项目组接过来的一个老项目,这几天依赖方突然报障,有一个接口一直超时调不通,被用户投诉升级为重大故障。
因为是在我之前就交接过来的而前这个项目就没修改过代码所以对此业务不了解,人最怕自己不熟悉的,悲剧。。。
2.解决过程
分析过程:
这时候只能硬着头皮上先解决问题,先看接口的调用链,发现在执行sql的prepareStatment调用链就断了,这时候就初步怀疑是sql问题。
因为本地没代码去仓库拉代码看看这个方法做了什么事, 简要的说下这个超时的方法做了什么事:
select count(*) from a where status= 0 and group_id=12 and b_type in("12342","22342","32342")
select * from a where status= 0 and group_id=12 and b_type in("12342","22342","32342")
稍微描述一下这个方法就根据几个条件查了一张单表 ,把数据多少和数据返回,这么简单尽然会出事。。。fuck,这也更加验证了慢sql的猜想。保险期间用postman复现了一下,确实转圈圈出不来。
解决过程: 这时候做了几件事
1.找dba执行了上面的sql确实执行耗时平均达到40秒左右。
2.看了看线上的表schema ,发现研发人员在status上加了一个索引,group_id上加了一个索引,并且这张表数据量在2000万左右。
3.写了几条sql:
#===========执行结果0.00
select count(distinct status)/count(1) from a
#===========执行结果2
select count(distinct status) from a
#===========执行结果0.00
select count(distinct group_id)/count(1) from a
# ============执行结果 132
select count(distinct group_id) from a
从上面的结果可以看出索引选择率为0,索引失效。当时就想爆粗口,真的有人尽然在这种类似男女这种枚举字段建索引。
这时候博主再次审视这条sql,因为不懂业务所以只能寄希望在where后面的b_type字段希望别在一张表里又几个,其实当时还是心里有数的,如果真的是几个,那这个接口的业务意义在哪,到这时候也大致明白了这sql的业务含义先通过group_id过滤出表中数据 再在这个group里查找 b_type等于in里面的条件数据,既然2000万的数据group_id有120几个,那么必然b_type肯定会有不少不一样,
说干就干。写出如下sql:
#===========执行结果0.112
select count(distinct b_type)/count(1) from a
#============执行结果 1832321
select count(distinct b_type) from a
选择率明显上来了,通过上面也验证了博主的猜想,于是提写出了如下策略:
#方案1
CREATE INDEX `idx_b_type` ON a(`b_type`)
#方案2
CREATE INDEX `idx_group_b_type` ON a(`group_id`,`b_type`)
最终选择了方案2,因为线上的索引比较多,所以选择,并且把线上原来的 group_id 索引删了。该方案在200万数据量的测试环境验证从20几秒降到了3ms,这是多少倍的效率提升。。。。。。。后话:
1. 因为2000万的数据量比较大,所以要选择用户使用少的时间点静悄悄的执行。不然再把mysql搞hang住了。当然网上有大表加字段等的操作方式,可以自行查找。
2. 线上该索引上线后,依赖方反馈,性能直线提升,从调不通到ms级别
您的支持是我创作最大的动力,敬礼
在接手一个老项目后,遇到一个接口因SQL查询超时引发重大故障。分析发现是由于一个简单的单表查询操作执行缓慢。经过排查,确定是索引选择率低导致的问题,尤其是对status和group_id字段的索引并未有效利用。通过执行不同的SQL测试,确认b_type字段的选择率更高。提出了创建针对b_type的单字段索引和group_id、b_type的复合索引两种解决方案,并最终选择了后者。在测试环境中,查询时间从20几秒降低到3ms,显著提升了性能。在线上部署后,接口性能得到了显著提升。
1万+

被折叠的 条评论
为什么被折叠?



