【问题标题】:How to paginate query results ordered in descending order如何对按降序排列的查询结果进行分页
【发布时间】:2014-08-09 14:18:31
【问题描述】:

我正在构建我的应用程序的后台,我想按 id 降序排列最后 20 个用户。

我在我的页面中实现了无限滚动,所以每次管理员点击页面底部时,都会通过 Ajax 发送一个新请求以检索以下 20 个用户等……直到我们获得第一个用户.

总结一下,这里有几个查询:

select * from users order by id desc limit 0, 20
select * from users order by id desc limit 20, 20
select * from users order by id desc limit 40, 20
...

但问题是我按降序排列用户。所以如果一个新用户在我滚动时注册,我每次发送请求都会得到重复的结果。

假设我的用户列表如下,我的限制是 3(而不是 20)

1. Pierre
2. Paul
3. Jack
4. Jean
5. Mike
  • 第一个查询将给我:Mike、Jean、Jack
  • 第二个:保罗,皮埃尔

但如果用户“Carla”在两个请求之间注册:

  • 第一个查询仍然会给我:Mike、Jean、Jack
  • >> Carla 注册并获得 ID 6
  • 第二个:杰克、保罗、皮埃尔

结论是,我的表中会出现两次“Jack”记录。

这个问题看起来很可笑,但你知道如何避免吗?

PS : 我不知道你是否注意到了,但 Facebook 似乎有一个类似的问题,当你向下滚动新闻提要时,你可以看到多次相同的项目。这一定是一个更复杂的问题,但想法是一样的。

【问题讨论】:

  • 是的,我愿意(使用 Ebean 作为 ORM),但我将问题保留为通用问题,因为它更多的是算法问题,而不是特定于数据库的问题。
  • 例如LIMIT 并非在所有 DBMS 中都可用,通常在发布问题时使用标签 mysqlsql 会更容易。 ORM 也可能很有趣。

标签: mysql sql pagination ebean


【解决方案1】:

我认为您基本上有两种现实的方法来解决这个问题。一种不切实际的方法是在浏览时锁定表——然后新用户无法进入。另一种方法是在每个用户启动页面时为他们创建一个临时表。呸!

第二个是在用户注册时打上时间戳。然后获取此时间戳并将其用于滚动。您需要从数据库中获取时间戳,以避免应用端和数据库端的时间略有不同。比如:

select now() as as_of_date

然后将其放入一个变量中并将查询更改为:

select * from users where CreationTime <= @as_of_date order by id desc limit 0, 20;
select * from users order CreationTime <= @as_of_date by id desc limit 20, 20;
select * from users order CreationTime <= @as_of_date by id desc limit 40, 20;

请注意,在最新版本的 MySQL 中,您可以将当前时间设置为 datetime 时间的默认值(而不必为此处理 timestamp)。

【讨论】:

  • 您的回答让我朝着正确的方向前进,谢谢。我最终使用maxId 作为光标。也许我错了,但 id 已编入索引,所以我认为请求比使用对象的创建时间更快。
  • 是的,它们是递增的
【解决方案2】:

如果您不想看到新创建的用户,解决方案会相对简单。如果 ids 是自动序列 - 您可能会在运行检索查询之前捕获 max(id),并将您的查询更新为 -

select * from users where id <= max_id order by id desc limit 0, 20

您也许可以对time stamp 执行类似操作 - 如果表格上有last_created 的列。

如果您想在输出中包含新创建的用户而不重复结果,则需要额外的逻辑。

希望这会有所帮助。

【讨论】:

  • 我使用最大 id 解决了这个问题,将其视为游标。每次我获取一个页面时,我都会保留最后一个元素 id 并在下一个请求中发送它,直到它的值为 0。这意味着我获取了所有记录。感谢您的帮助。
【解决方案3】:

试试这个

SELECT * FROM users WHERE id < PREVIOUS_LIST_LAST_ID ORDER BY id DESC LIMIT 3

对于每个请求,我们都可以发送 id,这表明直到这个 id 我们已经显示了结果。

但是如果你也想显示新插入的记录,你可以试试

SELECT * FROM users WHERE id < PREVIOUS_LIST_MIN_ID OR id > MAX_ID
    ORDER BY id DESC LIMIT 3

在这种情况下,MAX_ID 将是页面上可见的第一条记录的值

【讨论】:

    猜你喜欢
    • 2011-09-28
    • 2019-12-23
    • 2017-05-09
    • 1970-01-01
    • 2022-08-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    相关资源
    最近更新 更多