InnerJoin分页导致的数据重复问题排查
2016年8月9号美好的七夕的早上,我精神抖擞地来到公司。一会之后,客服宅宅MM微信我,说一个VIP大店铺订单导出报表中一个订单有重复行。于是,我赶紧开始查探问题所在。经过一天的反复仔细追查(当然还包括各种事项的打断),终于发现这个问题的原因所在。。。
有个订单主表 o,以及一个订单商品表 i ; o 与 i 是一对多的关系:其中一个订单 d_no 会对应多个商品 t_id,而一个商品 t_id 仅对应一个订单 d_no. 那么问题在哪里呢? 有经验的同学可能已经猜到是什么原因了,不过且让我们一步步来看:
首先,肯定是复现问题。很幸运,在重复执行后,确实如商家所言,这个订单的相应商品行都重复了一次。那么,怎么排查呢? 显然要在应用程序的不同地方里打印这个订单的信息,看看究竟是从哪里开始重复的,通过一步步向源头追踪,发现从获取订单号的最源头的地方就有重复了。我开始以为是这个订单本身有特殊的地方,因此让商家只导出这个订单,然而没有重复;这说明很可能是这个订单与多个订单一起导出才导致的问题。我又怀疑是不是这个订单的重复行有某个细节地方是不一样的才重复,然而做对比后发现完全一样;
现在似乎有点扑朔迷离了。于是,我觉得应该同时打印相应的SQL以及出现该订单的信息。在重复运行多次、打印相关信息并仔细观察之后,发现这个订单在以下两个查询中分别出现了一次; 在第一个SQL结果的第一个,以及第二个SQL结果的最后一个。边界出现问题了。
select o.d_no from o, i
where o.d_no = i.d_no and `o`.`dianpu_id` = ?
and `o`.`xiadan_time` >= ? and `o`.`xiadan_time` <= ? and `i`.`shangpin_id` = ?
order by i.d_no desc limit 1400,50; select o.d_no from o, i
where o.d_no = i.d_no and `o`.`dianpu_id` = ?
and `o`.`xiadan_time` >= ? and `o`.`xiadan_time` <= ? and `i`.`shangpin_id` = ?
order by i.d_no desc limit 1350,50;
我终于意识到: 很可能是 Join 分页导致的问题。是不是代码分页有微妙的 Bug ? 看了下代码,没看出问题;疑问又来了: 为什么单单这个订单会重复,其它的不重复呢? 为什么搜索页面不重复,而导出报表会重复呢?按理来说,这个订单号没有特殊之处,那么别的订单号完全也可能重复;并且搜索与导出共用的相同的接口逻辑;重复抽查了几个 limit X, 50, 没发现重复的其他订单号; 于是,注意力还是转回到这两个SQL 。
究竟暗藏什么玄机? 我甚至怀疑与主键 id 值的缺漏有关,打印出 id 值后看不出什么特别的规律,很快否定了这个想法。 于是我直接在DBA界面系统打印出这两个SQL的结果,看着重复的d_no排序输出在界面上,突然灵光一闪,意识到了。。。
我执行了以下SQL,直接打印出这个查询条件下的所有 d_no,查看重复订单号的位置。
select o.d_no from o, i
where o.d_no = i.d_no and `o`.`dianpu_id` = ?
and `o`.`xiadan_time` >= ? and `o`.`xiadan_time` <= ? and `i`.`shangpin_id` = ?
order by i.d_no;
你明白了么? 这个订单号对应两个商品,因此查出来这个订单号会出现两次,而这两次正好出现在两次查询的边界处。在 1399 的偏移量时,查出来一次,在 1400 的偏移量时,查出来一次; 因此,这个订单号会查出两次,而根据这个订单号获取其他信息后也会导出两次,订单导出是每个 limit X, 50 都会增量地导出到报表里,从而出现了最终报表中的重复行(在搜索接口中会有去重后返回给前端)。 其他的订单号之所以没有出现问题,是因为在临界处 50*X,50*X-1 处的订单号正好只对应一个商品,只会出现一次,因此避免了重复行。话说回来,其实导出报表订单重复行的概率还是比较高的,只要在 50*X, 50*X-1 出现的订单号是有对应多个商品的,就很可能在最终报表中有重复行。这个还是要看运气滴~~
问题原因定位了,解决就简单了。将 select o.d_no 改成 select distinct(o.d_no) 即可;当然,对应的 count 也要改成 count(distinct(o.d_no)) .
排查问题经验总结:
1. 排查问题的重点是找到:位置和原因;
2. 日志非常重要,在关键路径和关键状态上打关键信息日志,好过十打的代码分析和肯定应该Maybe。关键路径会帮助你排除不出错的地方,缩小问题范围,关键状态会减少需要做出的猜测,更肯定地排查问题; 关键信息或关键词能让人很快锁定问题出现的代码位置。
3. 根据经验分析可能的原因,然后采取技术手段去找到位置和原因。 排查的手段通常是: 复现问题,重复执行,静态分析,猜测原因,断点运行;
4. 问题对象是否有特殊性?针对对象本身单独进行探查;
5. 边界处一定要重视,常常是问题产生的多发地;
6. 先到此为止,睡觉!
ps: 偶滴七夕啊。。。虽然没有美女作伴,也不能这么开玩笑啊。。。
InnerJoin分页导致的数据重复问题排查的更多相关文章
- Asp.net并发请求导致的数据重复插入问题
前段时间工作中,有客户反应了系统中某类待办重复出现两次的情况.我核实了数据之后,分析认为是并发请求下导致的数据不一致性问题,并做了重现.其实这并不是一个需要频繁调用的功能,但是客户连续点击了两次,导致 ...
- Oracle分页查询排序数据重复问题
参考资料: http://docs.oracle.com/database/122/SQLRF/ROWNUM-Pseudocolumn.htm#SQLRF00255 http://blog.csdn. ...
- Mybatis oracle多表联合查询分页数据重复的问题
Mybatis oracle多表联合查询分页数据重复的问题 多表联合查询分页获取数据时出现一个诡异的现象:数据总条数正确,但有些记录多了,有些记录却又少了甚至没了.针对这个问题找了好久,最后发现是由于 ...
- oracle 分页查询数据重复问题
最近在做项目的时候发现一个问题,oracle 在查询分页数据的时候,有几条数据重复查询了,并且有几条数据在分页的时候消失了.百度了一下发现,ORACLE 在查询数据的时候返回的行不是固定的,他只是按照 ...
- 为什么MYSQL分页时使用limit+ order by会出现数据重复问题
问题描述: MYSQL采用limit进行翻页查询时,搭配order by ,在翻到第二页的时候可能会出现第一页的数据, 示例sql如下: select a,b from c where d = ' ...
- iOS不得姐项目--推荐关注模块(一个控制器控制两个tableView),数据重复请求的问题,分页数据的加载,上拉下拉刷新(MJRefresh)
一.推荐关注模块(一个控制器控制两个tableView) -- 数据的显示 刚开始加载数据值得注意的有以下几点 导航控制器会自动调整scrollView的contentInset,最好是取消系统的设置 ...
- postgresql排序分页时数据重复问题
当同时排序又分页时,如果排序的字段X不是唯一字段,当多个记录的X字段有同一个值时顺序是随机的. 这个有可能造成分页时数据重复的问题.某一页又把上一页的数据查出来了,其实数据库只有一条记录. 解决办法: ...
- Hibernate分页功能数据重复问题
今天遇到一个很憋屈的问题那就是hibernate分页查询中出现重复数据,本来一直没有在意,以为是数据问题,但是一查程序和数据都没有问题,继续深入查看,找到问题了就是order By 时出的问题,唉.. ...
- postgresql-分页数据重复问题探索
postgresql-分页数据重复探索 问题背景 许多开发和测试人员都可能遇到过列表的数据翻下一页的时候显示了上一页的数据,也就是翻页会有重复的数据. 如何处理? 这个问题出现的原因是因为选择的排序字 ...
随机推荐
- 3Sum Closest
Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...
- 生成一行html
//压缩 一行html Regex regReplaceBlank = new Regex(">(\\s+)<", RegexOptions.IgnoreCase); ...
- 【iCore3 双核心板】例程十七:USB_MSC实验——读/写U盘(大容量存储器)
实验指导书及代码包下载: http://pan.baidu.com/s/1qXt1L0o iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...
- ext3grep 模拟恢复删除文件
一,下载ext3grep-0.10.1.tar.gz 点此下载 二,安装 #tar zxvf ext3grep-0.10.1.tar.gz #cd ext3grep-0.10.1 #./configu ...
- 如何使用 vimdiff 来 git diff /svn diff
#git 如何实现vimdiffgit config --global diff.tool vimdiff git config --global difftool.prompt false git ...
- SQL ORDER BY 子句
ORDER BY 语句用于对结果集进行排序. ORDER BY 语句 ORDER BY 语句用于根据指定的列对结果集进行排序. ORDER BY 语句默认按照升序对记录进行排序. 如果您希望按照降序对 ...
- 远程出发jenkins jobs
wget -O - -q "http://jenkins_server/job/ttt/buildWithParameters?TEST1=Value" wget -O - -q ...
- Nginx配置(日志服务器中关于日志的产生)
一:概括 1.需要配置的概括 定义日志格式 日志的分割字段:^A 日志格式:IP地址^A服务器时间^A请求参数 配置location,记录请求日志到本地磁盘 将数据按照给定的日志格式存储到本地磁盘 二 ...
- 集合中list、ArrayList、LinkedList、Vector的区别、Collection接口的共性方法以及数据结构的总结
List (链表|线性表) 特点: 接口,可存放重复元素,元素存取是有序的,允许在指定位置插入元素,并通过索引来访问元素 1.创建一个用指定可视行数初始化的新滚动列表.默认情况下,不允许进行多项选择. ...
- node crypto md5加密,并解决中文不相同的问题
在用crypto模块时碰到了加密中文不相同的问题,多谢群里面@蚂蚁指定 1:解决中文不同的问题 function md5Pay(str) { str = (new Buffer(str)).toStr ...