暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

每到月初系统就出问题是怎么回事

白鳝的洞穴 2022-11-07
386
上周五早上写了一篇关于索引的文章,有些研发出身的朋友确实对索引的工作原理不甚了解。我们的系统中也往往因为索引设计的问题不合理而经常出问题,这些问题大多数是研发部门对索引的原理掌握不够引起的。索引的问题,上线后再来解决是比较麻烦的。可能有些DBA会说,那有啥麻烦的,缺索引就加呗,这不是我们常干的事情吗。确实是的,发现一条SQL性能不好,就加一条索引,立马就药到病除。而缺乏对应用特点的了解加的索引,缺乏统筹管理,久而久之系统中就会出现一些十分类似的索引,这样的索引多了,也不见得是件好事情,SQL执行计划中用错索引的事情就会多起来了。这时候如果需要删除某条索引或者合并某几条索引,就不是那么容易做出决定的了,弄不好今天刚刚做完变更,第二天某条不知名的SQL突然就出问题了。所以索引的问题,最好还是由应用开发商统筹搞是最佳选择。而因为我们的开发商对索引原理和应用的技术并不精通,导致采用这样最佳选择的系统并不多。
上周一个客户的系统出了一个性能问题,CPU使用率100%了,系统变得很慢。他们上了APM等一系列的监控工具,因此很快定位到是某个业务引发了该问题,把该业务临时关闭后系统恢复正常。不过这个业务是签到业务,十分重要,和赠送积分和费用减免相关的,是确保该APP能够日活几百万的关键业务。因此关闭该业务并不是很好的选择,必须尽快回复业务。经过数个小时的分析,他们发现该业务的一条SQL的执行计划出错,这是一条对一张很大的分区表做的查询,出问题的时候使用了一个不合理的索引,导致原本只有十几个逻辑读的SQL,逻辑读上升了1000倍。
事后他们问我可能会是什么原因,我说让我猜测一下,应该你的这条SQL应该使用userid索引而出错的索引是日期型的分区主键。客户十分惊讶,说我都没和你说细节,你咋猜的这么准呢?实际上类似问题在我做DBA的这二十多年里,遇到的已经太多了。自从用户开始使用分区表以来,这个问题的出现就越发多了起来。
这种签到业务,一般是会有查询某个userid当天是否已经签到或者最近一段时间签到了多少次的操作。而这种查询里往往会包含userid和sign_date这两个字段的查询条件。而sign_date之类的日期类型往往又是分区主键字段。此类业务在切换新分区的时候,也是最容易用错索引的时候。
比如说这张表每天晚上23:30做表分析,10月31号的时候,表分析会认为11月份的分区是空的,没有任何数据。因此如果查询userid=$1 and sign_date>=$2 and sign_date<$3这样的条件是,如果userid和sign_date都存在索引,那么如果$2>=11月1日,则CBO会认为这个查询中符合sign_date的条件的记录数是0条,因此认为使用sign_date扫码的成本最低。而随着11月1日签到人数量增加,很可能会扫码出上百万符合条件的记录,然后再回表去查找userid是否符合条件。而如果我们使用Userid的索引去扫描,哪怕userid索引被建成Local索引,因为存在sign_date的条件,因此通过分区裁剪,也可以定位到只扫码1-2个分区,顶多找出几十条满足userid条件的记录来。执行成本肯定是远远低于使用sign_date的。
上面的情况只是其中一种情况,如果我们是在11月1号2点做的表分析,那么11月的分区可能有数据了,但是分区里的数据量可能不多,因此也可能因为COST的细微差别,导致选错索引。无论哪种情况发生,都会导致业务应用性能的不稳定。
而这种原本开销很小的SQL的执行开销虽然增大了上千倍,当CPU没有爆掉的时候,可能我们也还无法发现,因为很可能原本执行5毫秒的SQL变成了300毫秒,对单一用户的体验感受不大。不过如果CPU爆掉后,情况就不一样了,整个系统就会变慢,所有业务都会受到影响。
听完我的解释后,客户认为这个和他们的现象十分类似。并认为这是运维部门的责任,因为没有及时更新表分析数据。我却认为从根上来说,运维部门很可能都是使用的默认的表分析策略,根本没有这方面的特殊处理,因此责任也并不完全是运维部门的。研发单位的责任也很大,如果在设计索引时候认真一点,设计一个sign_date+userid的复合索引,而不要使用目前这种两个单列索引的设计,这种问题就不会出现了。过多的相互干扰的索引,往往是导致CBO用错索引的最根本的原因。十年前,在一个银行用户那我也遇到过这样的问题,出问题的表上有十几个索引,我建议他们梳理一下,删除几个容易用错的索引,但是他们根本不敢在核心交易系统上做索引的删除操作。于是只能在每个月1号的早上4点增加了一个对这张表做表分析的定时任务,来避免类似问题的发生。
对于运维单位来说,这类问题是防不胜防的。除了做好索引设计和优化表分析策略之外,对于此类问题还需要做好关键SQL跟踪,以及类似问题的监控告警。如果一些关键SQL出现执行计划、执行开销、执行次数突变的时候,能够及时告警。当系统的逻辑读突发大幅增加的时候能够及时告警,当某个SQLID执行并发数突发增长时能够及时告警,那么,此类问题一旦发生起码我们就可以及时发现,及时定位,及时处置了。


文章转载自白鳝的洞穴,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论