月的某天下午,某用户反馈,医生站首页中病案附加项目的顺序乱了,影响医生的正常工作。
从跟踪出来的看的到,执行得到的数据没有按预期的方式排序,但是,相同的在测试库运行却能得到正常排序的结果。
院方近期没有做什么调整,怀疑跟一个月前我们转移历史数据之前的一系列性能优化调整有关。
经过一番分析,最终,通过重新收集该涉及到的表的统计信息后,问题得到解决。
感觉有点儿不可思议吧?
统计信息收集不正确,还会影响产品功能的正常性?
有些事情的真相并不是我们看到那样,就像鸡血在磨心上点了几下之后,小孩的肚子就不痛了,如果你相信这样的巫术,可能会影响到你对很多事情的判断,有时,我们看到的并不一定是真相,倒不是因为对未知的知识缺乏敬畏,而是基本的逻辑推理问题,以及探寻真相的钻研精神。
统计信息收集确实是解决很多性能问题的一副灵药,但对这个问题来说,收集统计信息只是其中的一种临时解决办法,根本的原因还是书写方面存在问题。
下面我们来一步一步解开事情的真相。
语句如下:
序号编码名称内容病案项目编码
多么简单的,不像那些需要翻几页才能看得完整的变态,这种简单的除了理解起来更节约时间之外,还减少了很多可能导致验证结果偏差的干扰。
按开发人员的预期,先排序再对结果集进行编号,作为下特有的“伪列”,作用就是根据数据结果行数产生一个从开始递增的行号。
有一定基础的同学可能一下就看出的不对之处:
和在同一层次时,排序是最后执行的,先取行号自然就无法得到想要的按排序结果递增的行号,所以,如下所示,序号列就是“乱序”的。
那么,问题来了,既然这个有问题,为什么在测试库运行又是正常的呢?
近期产品中的这条也没有做过修改,为什么以前是正常的,现在却突然出现问题了呢?
没有骗你哟,用户发来了测试库上执行后结果正确的截的图。
刚开始看到这个现象,也是很纳闷,会不会是数据库的什么参数影响了排序,像经常遇到的“_gby_hash_aggregation_enabled”这个参数对排序的影响(后续可能会写一个这方面的案例),问题是这个里没有子句。
从数据库的基础理论方面想了想,影响排序的还有哪些因素呢?
如果是有索引,那么索引本身就是排了序的,读取数据时就不需要排序了,再用取值,是不是就可以取到预期的结果了呢?
也就是说,变相实现了先排序,后取序号的作用。
为了证实这一点,在公司的测试库上做了一个验证:
相同的,执行结果跟用户测试库的结果是一样的,序号正常排序。
禁用主键”病案项目”以“编码”字段为索引后,执行结果跟用户正式库的结果一样,序号排序就乱了,再现了问题。
病案项目病案项目
恢复主键后,序号就正常排序了。
病案项目病案项目
是不是用户生产库的主键被禁用了,索引丢了吗?
转移历史数据期间,的确会禁用一些约束,但是这张表并不是转出相关的表呀!而且转完数据后,我们恢复约束后也做过检查。
会不会是用户后期运行过程中,某种原因导致该索引无效了呢?
马上查询用户的生产库,主键是有效的,索引也是有效的。
眼看找到一条路,没想到走到底发现是个死胡同,不要懈气,既然问题再现了,原理也清楚了,顺着这条路,仔细找,找一定有出路。