最近在帮一个同事调试BUG,有一个条BUG是这样描述的: 所有有排序功能的列表,当其中某一字段当前页面内容一致时,翻页就有误。 页码改变,列表内容不变。
看到这个BUG第一反应是查看翻页的SQL语句。调试后找到SQL语句为:
SELECT * FROM ( SELECT BIZ.*,ROWNUM RN FROM (SELECT * FROM WIKI_BIZ B WHERE B.BIZ_SYNC_TYPE < 3 ORDER BY B.BIZ_VIEW_COUNT ASC) BIZ WHERE ROWNUM <= 20 )WHERE RN >=11; SELECT * FROM ( SELECT BIZ.*,ROWNUM RN FROM (SELECT * FROM WIKI_BIZ B WHERE B.BIZ_SYNC_TYPE < 3 ORDER BY B.BIZ_VIEW_COUNT ASC) BIZ WHERE ROWNUM <= 30 )WHERE RN >=21;
查询后的结果为:
<
BIZ_ID | BIZ_SYNC_CODE | BIZ_SYNC_NAME | BIZ_SYNC_TYPE | BIZ_SYNC_TIME | BIZ_SYNC_FROM | BIZ_VIEW_COUNT |
32278 | BP4192 | 手机悦读会会员包 | 2 | 2012-1-5 3:04 | 1 | 0 |
32277 | SP004385 | 中国移动;北方手机报 | 2 | 2012-1-5 3:04 | 1 | 0 |
32276 | MP0362 | 彩铃音乐盒《三分贝兑换铃音包(1区)》 | 2 | 2012-1-5 3:04 | 1 | 0 |
32275 | CP13D6 | 动感地带网聊套餐(139邮箱,彩铃,飞信,彩信账单) | 2 | 2012-1-5 3:04 | 1 | 0 |
32274 | SP000481 | 中国移动;泰州手机报 | 2 | 2012-1-5 3:04 | 1 | 0 |
32268 | SP005722 | 移动梦网自有游戏;丰尚佳诚5元包月游戏套餐 | 2 | 2012-1-5 3:04 | 1 | 0 |
32267 | SP008506 | 中国移动;手机报-M-zone英语(大学版)(0元版) | 2 | 2012-1-5 3:04 | 1 | 0 |
32261 | BP1142 | 12580彩信-掌上折扣 | 2 | 2012-1-5 3:04 | 1 | 0 |
32258 | CP00P1 | 新全球通 | 2 | 2011-12-15 3:04 | 1 | 0 |
32251 | BP1701 | 索乐测试包 | 2 | 2011-12-15 3:04 | 1 | 0 |
两条SQL语句的查询结果一模一样 !
当时我也不知道为什么结果为一模一样,但是注意到BIZ_VIEW_COUNT的值都是0。就猜想是排序列不唯一造成的排序不稳定造成的。 后来去网上查找有没有类似的问题。发现也有很多人遇到这个问题,并且进行过讨论。解决的方法很简单,就是 把排序的内容弄成唯一的 。我试了排序的时候加上ROWID,或者WIKI_BIZ的主键BIZ_ID,问题得到解决。
解决方法:把排序的内容弄成唯一的! SQL语句如下:
SELECT * FROM ( SELECT BIZ.*,ROWNUM RN FROM (SELECT * FROM WIKI_BIZ B WHERE B.BIZ_SYNC_TYPE < 3 ORDER BY B.BIZ_VIEW_COUNT ASC,ROWID/***或者B.BIZ_ID***/) BIZ WHERE ROWNUM <= 20 )WHERE RN >=11;
后来又看到有人讨论ORACLE是怎么进行排序的,导致结果一模一样。根据讨论者的思路写了几个SQL,发现排序也是很有规律的。SQL语句如下:
SELECT RID, ROWNUM FROM (SELECT ROWID RID FROM WIKI_BIZ B ORDER BY B.BIZ_VIEW_COUNT) WHERE ROWNUM <= 30; SELECT RID, ROWNUM FROM (SELECT ROWID RID FROM WIKI_BIZ B ORDER BY B.BIZ_VIEW_COUNT) WHERE ROWNUM <= 40; SELECT RID, ROWNUM FROM (SELECT ROWID RID FROM WIKI_BIZ B ORDER BY B.BIZ_VIEW_COUNT) WHERE ROWNUM <= 50;
分别按照BIZ_VIEW_COUNT排序查找前30、40、50条数据。结果却是第一个结果集的第2-30条数据是第二个结果集的12-40条数据。第二个结果集的第2-40条数据是第3个结果集的第12-50条数据(BIZ_VIEW_COUNT都为0)。由此不难找出一些规律。但是发现网上有人查出的数据又和这个规律有略微的不同。望高人解答一下ORACLE的排序算法。