当'order by'非确定性时,sql分页

时间:2016-06-10 15:23:56

标签: sql oracle pagination paging 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>>`

如果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;

大多数时候我只是觉得这很整洁。我在其他帖子中没有看到太多副作用。

而且,我想知道我能做些什么......以及其他策略是否会增加处理时间。

来自戈登的

解决方案,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;

stackoverflow的另一个胜利,谢谢gentelmen,快乐编码每个人

1 个答案:

答案 0 :(得分:5)

SQL表表示无序集。因此,SQL排序不是稳定。也就是说,具有相同键值的行可以按任何顺序排列 - 并且在多次运行中,顺序可以更改。行没有“基础”订单。

解决方案是在order by的末尾添加唯一ID。这永远是最后一把钥匙:

select *
from (select a.*, ROWNUM as rnum
      from ( select * from xsd order by PREFIX asc, id ) a
      where ROWNUM <= 40
     )
where rnum  >= 30;

这是否会影响性能取决于索引是否可用于排序。如果没有使用索引,则效果应该非常小。但是,如果添加额外的密钥可以防止使用索引,那么影响就会大得多。