记一次奇异的bug
很久以前,写过一个java版通用Excel导出插件。最初版本中,从数据库获取数据是一次性获取。刚开始没什么问题。使用几年以后,用户反馈下载长时间范围的数据,会非常卡,甚至会出现错误。
性能问题,做了一次分析后,发现主要是读取数据用时非常长。使用了几年,数据库中的数据超过千万,下载查询是否会使用到索引,这个不可控。基于此,想到了分页读取生产的思路。
改好代码测试无误,上线有几年了。昨天用户反馈,下载的数据内容有问题,有些数据重复,有些数据缺失,但是总条数又对的上,而且连续两次导出的文件,内容有差异。
脑子的第一反应就是,用户是不是使用了表关联导致的。去现场仔细查看前端页面配置,没有用到任何表关联。加之用户不懂it,在叙述中只是讲业务如何核对数据,而我恰巧也忘记了加分页读取的事。所以一直在业务数据异常和sql异常两者之中徘徊。最终无果之下,跟客户讲,我回去捋一下代码逻辑看看,并且让他们把db的内容备份给我。
回到座位,点开代码一层层核查,在代码中看见了分页,顿时脑子中想到了以前解决过的一个bug。sqlserver数据库,在分页查询的时候,一定要使用orderby,不然记录出现的顺序会有一定的随机性,正好符合客户描述的现象。我核查dao层代码,发现有在前端未传递排序字段的情况下,给予默认排序字段,该字段为create_date。拿着sql在库里查询,发现有大量相同create_date的记录。于是跟用户讲,代码有缺陷,讨论得出我再统一插件中进行修改。将id加入排序字段内。
在所用使用到这个通用导出模块的地方,都有id字段,且id字段唯一。这样修改即可解决问题。
这个问题的关键就在于,数据库排序在多次执行时,会将排序字段完全相同的数据随机返回。解决的关键就在于,使用唯一键或者主键来防止出现这种情况。