基于检索到的最后一条记录的SQL分页

时间:2014-06-21 21:04:42

标签: sql ruby-on-rails postgresql pagination sql-order-by

我需要实现对分页之间数据变化具有半弹性的分页。标准分页依赖于SQL的LIMITOFFSET,但是随着新数据点的创建或排名在排序中的变化,偏移量可能会变得不准确。

一个想法是保留API请求的最后一个数据点并获取以下元素。我真的不知道SQL(我们正在使用postgres),但这是我(确实有缺陷)尝试做类似的事情。我试图将最后一个元素的位置存储为'rownum',然后在以下查询中使用它。

WITH rownum AS (
 SELECT *, ROW_NUMBER() OVER (ORDER BY rank ASC, id) AS rownum 
 WHERE id = #{after_id}
 FROM items )
SELECT * FROM items
OFFSET rownum
ORDER BY rank ASC, id
LIMIT #{pagination_limit}

我可以看到一些问题,比如最后一项是否在等级上发生了显着变化。如果有人能想出另一种方法来做到这一点,那就太好了。但是如果可能的话,我想将它限制在单个数据库查询中,因为这是应用程序最常见的API。

2 个答案:

答案 0 :(得分:1)

您的整个语法不太有用。 OFFSET来自ORDER BYFROM来自WHERE等。

这个更简单的查询将执行我认为你的代码应该做的事情:

SELECT *
FROM   items
WHERE (rank, id) > (
   SELECT (rank, id)
   FROM   items
   WHERE  id = #{after_id}
   )
ORDER  BY rank, id
LIMIT  #{pagination_limit};

比较复合类型(rank, id)可保证相同的排序顺序。

确保您拥有两个索引

  • (rank, id)上的多列索引。

  • (id)上的另一个 - 你可能已经对列进行了pk约束。 (具有前导id的多列索引也可以完成这项工作。)

有关索引的更多信息:
Is a composite index also good for queries on the first field?

如果 rank不易变,那么额外参数化它而不是动态检索它会更有效 - 但rank的波动性似乎是你的点审议......

答案 1 :(得分:0)

我现在认为解决此问题的最佳方法是存储原始查询的日期时间,然后在后续查询后过滤掉结果,从而确保偏移量大部分正确。也许可以使用持久数据库来确保数据处于与原始查询相同的状态。