【问题标题】:Pagination on fast changing database content对快速变化的数据库内容进行分页
【发布时间】:2012-03-12 18:33:35
【问题描述】:

我需要使用分页读取 MS SQL 数据库表的内容,即获取 N 行的第一页,然后是 N 行的第二页,依此类推。

如果在分页过程中数据库的内容发生显着变化,一个简单的分页查询,如:

SELECT *
FROM (SELECT a.*,
    ROW_NUMBER() OVER (ORDER BY id) AS rnum
    FROM articles a)
WHERE rnum <= 10
AND   rnum >= 6;

可能无法可靠地工作。插入的行可能会被跳过或导致后续行重复,而删除的行可能会导致后续行被跳过。

我可以通过执行以下任一操作来避免此类问题:

  1. 在整个分页期间锁定行以防止更新 - 限制性的
  2. 在分页前将行复制到临时表 - 太慢了
  3. 按行号和排序值的组合选择 显示在上一页的末尾,在 根据变化表的适当位置,但仍然得到 只有接下来的 N 行

我有点喜欢第三种解决方案,但是当排序列中有重复值时,我发现很难实现。

例如,假设我有一个按降序排列的文章列表。如果评分相同,则按 ID 升序排序(ID 是唯一的):

ID      RATING
9       34
3       32
6       32
8       32
12      32
1       25
2       23

现在,我想要 3 篇文章的页面,这意味着第一页将包含第 9、3 和 6 篇文章。这是通过从排序列表中查询前 3 篇文章来完成的。

现在,我想从第 8 条中恢复接下来的 3 篇文章,使用文章 ID 作为恢复位置的标记。

如果我告诉数据库取第 8 条的信誉,而不是取信誉低于此的 3 篇文章,我会跳过第 12 条。

如果我告诉数据库取第 8 条的信誉,而不是取信誉低于或等于该信誉的 3 篇文章,我会重复第 3 条和第 6 条。

我可以使用什么 SQL 查询(或查询组合)从文章 8 中恢复分页,使用文章 ID 作为恢复位置的标记?

【问题讨论】:

  • 不幸的是,您的要求不禁自相矛盾。您的目标是始终显示他们在本次会议中从未见过的文章,还是确保排名准确?如果我在看前 3 名,那么有人将 ID 8 更改为排名 33(将 6 推到第二页),您不想在第二页显示 6,因为他们已经看到了?如果他们再次转到第 1 页怎么办?
  • @AaronBertrand 好的,好点。我想向用户展示他们从未见过的文章。在这种情况下你会怎么做?缓存整个表格是在页面间提供一致结果的唯一解决方案吗?
  • 再说一次,我不清楚你的目标。您是否希望用户查看过时的数据,即使同时评级实际上已经改变?如果我在 eBay 上查看商品并且其中一件商品的出价上涨,我希望在出价之前对其进行准确的重新分类。那么您要解决的实际问题是什么?
  • @AaronBertrand 就我而言,真正重要的是列表中不重复一篇文章。这是因为这通常显示为逐页加载的滚动列表,而不是像书中那样单独的页面。因此,在滚动列表中,看到一篇文章两次会很糟糕,而在单独的页面中则不会那么糟糕。此外,在这种情况下,列表的静态快照也是可以接受的。
  • 因此,您似乎应该为该用户缓存结果(例如,您可以将 all 的 ID 发送到应用程序并让它一次只拉 3 篇文章fetch),但还要添加一个免责声明,如果他们需要半小时才能滚动列表,列表可能不再准确。

标签: sql sql-server database pagination


【解决方案1】:

将评论转换为答案,因为它似乎已经解决了用户的问题。

因此,您似乎应该为该用户缓存结果(例如,您可以将所有 ID 发送到应用程序并让它在每次提取时一次提取 3 篇文章),但还要添加一个免责声明,如果需要他们半小时滚动列表,列表可能不再准确。

【讨论】:

    猜你喜欢
    • 2020-07-20
    • 2014-09-25
    • 2012-03-25
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-22
    • 2012-10-01
    相关资源
    最近更新 更多