Ste*_*lds 2 sql oracle paging pagination sql-order-by
多年来我一直在使用相同的sql分页代码.我现在才注意到这种奇怪的现象......我认为它非常有趣,我们应该讨论它.所以这是标准的分页样板:
SELECT a.*
FROM (SELECT b.*,
rownum b_rownum
FROM (SELECT c.*
FROM some_table c
ORDER BY some_column) b
WHERE rownum <= <<upper limit>>) a
WHERE b_rownum >= <<lower limit>>`
Run Code Online (Sandbox Code Playgroud)
如果some_column是连续的,那么它的效果很棒.
但我暴露了这一点,并允许用户对任何列进行排序,如果他们碰巧选择了一些充满相同值的some_column,那么分页"会中断".
也就是说,查询将返回页面后相同的精确行数据页面.当我想到它时,为什么不呢.它可能只是选择最快的行或通过过滤器的任何东西.
例如,这些sql返回完全相同的数据
select *
from (select a.*, ROWNUM rnum
from ( select * from xsd order by PREFIX asc ) a
where ROWNUM <= 30
)
where rnum >= 20;
select *
from (select a.*, ROWNUM rnum
from ( select * from xsd order by PREFIX asc ) a
where ROWNUM <= 40
)
where rnum >= 30;
Run Code Online (Sandbox Code Playgroud)
大多数情况下,我只是认为这很整洁,而且我在其他帖子中没有看到太多副作用.
而且,我想知道我能做些什么......以及其他策略是否会增加处理时间.
来自Gordon,Alex的解决方案
只需将rowid添加为默认的最终订单.这些SQL现在不同了.我没有注意到响应时间的任何变化
select *
from (select a.*, ROWNUM rnum
from ( select * from xsd order by PREFIX asc, rowid ) a
where ROWNUM <= 30
)
where rnum >= 20;
select *
from (select a.*, ROWNUM rnum
from ( select * from xsd order by PREFIX asc, rowid ) a
where ROWNUM <= 40
)
where rnum >= 30;
Run Code Online (Sandbox Code Playgroud)
stackoverflow的另一个胜利,谢谢gentelmen,快乐编码每个人
SQL表表示无序集.因此,SQL排序不稳定.也就是说,具有相同键值的行可以按任何顺序排列 - 并且在多次运行中,顺序可以更改.行没有"基础"顺序.
解决方案是在结尾添加一个唯一的id order by.这永远是最后一把钥匙:
select *
from (select a.*, ROWNUM as rnum
from ( select * from xsd order by PREFIX asc, id ) a
where ROWNUM <= 40
)
where rnum >= 30;
Run Code Online (Sandbox Code Playgroud)
这是否会影响性能取决于索引是否可用于排序.如果没有使用索引,则效果应该非常小.但是,如果添加额外的密钥可以防止使用索引,那么影响就会大得多.