写点什么

Mysql 报表下载为什么出现了重复的数据?

用户头像
三石
关注
发布于: 2021 年 01 月 14 日
Mysql报表下载为什么出现了重复的数据?

某天,产品同学反馈了个生产问题:订单报表的下载功能,下载的数据里面少部分数据而且出现部分重复订单。纳尼?这么简单的一个单表数据下载,而且是历史悠久的老功能也能出现 bug。按开发惯例,首先怀疑产品同学使用下载功能的姿势不对。。。。。当然,这是玩笑。按产品同学提供的账号和条件重试了下载,果然 bug 复现,本着有问题解决问题的目的开始排查问题根源(数据安全考虑,举例使用表和数据都是模拟的)。

第一步,先从罪魁祸首的 SQL 分析

SELECT

  `ordercode`,

  `productcode`,

  `num`

FROM

 `t_order` WHERE productcode LIKE '10%'

LIMIT xnum, ynum ; 乍一看,一个很简单的 sql 语句,也不存在什么明显的问题。表结构如下:



试过几个 limit 参数,该 sql 的执行计划也是正常的,也都走了索引,难道索引本身有问题?



接着分析了几个有问题的下载文件,发现问题数据都是集中在文件的后面,难道是深度查询导致的问题?加大 limit 的取数位,重新看执行计划,果然问题出现了!



第二步,分析为什么出现这样的问题?

相信不少老司机已经知道问题的根源了,没错就是索引导致的!mysql 索引(innodb)的数据结构是个 B+树,叶子节点存放的键值是个有序的双向链表。sql 分页取前面的数据时,查询条件也是满足 index_2 的索引的,mysql 也忠实的执行了这个索引去取数据,当然取出的数据也是按索引字段 ordercode 排序的。虽然 sql 有潜在问题,但是数据量少的时候妥妥的不会出现任何问题,这也是为什么这个老功能一直正常的原因。

根据墨菲定律,会出错的事情一定会出错!当下载数据量很大的时候,就像上面有几十万的量,问题就出现了。原因就是 Mysql 的 limit x y 并不是像不少人当然的认为那样,像游标一样直接定位到第 x 条上,实际情况是要获取第 201000 到 202000 这 1000 条数据的时候会取出 202000 条数据的结果集再舍弃前面的 201000 条!这么大的结果集已经足够影响 mysql 的索引选择的策略,结果集占比整表数据量的比例过大,直接后果是导致索引失效,mysql 直接利用主键扫描全表取数据,而主键的顺序是以 id 这个字段来的,前后查询排序字段完全不一样,当然会存在取错数据行了!


第三步,解决问题

1.       方法 1:分页查询,前后执行索引不一致导致的,force index 强制使用 index_2 也可以解决,当然不推荐这么改,容易埋下隐患。

2.       方法 2:既然已经分析了最终根源是排序字段不一致导致的,sql 里面加个 order by 就可以解决问题

 

到此问题看似已经解决了,但是真的完美了吗???隐藏的彩蛋有待细心人发现。。。。


发布于: 2021 年 01 月 14 日阅读数: 36
用户头像

三石

关注

大道至简,知易行难! 2018.05.06 加入

我思故我在! 一个苏宁老兵的点滴记录

评论

发布
暂无评论
Mysql报表下载为什么出现了重复的数据?