分享

线上一个索引引起的重大故障

 Fengsq501u81r4 2021-11-30

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级别

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多