【问题标题】:SQL pagination based on last record retrieved基于检索到的最后一条记录的 SQL 分页
【发布时间】:2014-08-12 07:23:53
【问题描述】:

我需要实现对分页之间的数据变化具有半弹性的分页。标准分页依赖于 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。

【问题讨论】:

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    你的整个语法不太好用。 OFFSETORDER BY 之后。 FROM 出现在 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 的易变性似乎是您审议的重点......

    【讨论】:

    • 嗯,有趣!那么这会检索“after_id”之后的记录吗?
    • @light24bulbs:是的,根据ORDER BY rank, id。试试看吧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多