【问题标题】:Postgres pagination with non-unique keys?使用非唯一键的 Postgres 分页?
【发布时间】:2018-07-04 16:37:08
【问题描述】:

假设我有一个包含(索引)列id : uuidcreated : timestamp 的事件表。

id 列是唯一的,但 created 列不是。我想使用created 列按时间顺序走桌子。

类似这样的:

SELECT * FROM events WHERE created >= $<after> ORDER BY created ASC LIMIT 10

这里的$&lt;after&gt; 是一个模板参数,取自上一个查询。

现在,我可以看到两个问题:

  1. 由于created 不是唯一的,因此不会完全定义顺序。也许排序应该是id, created
  2. 每一行应该只在一个页面上,但是对于这个查询,最后一行总是包含在下一页中。

我应该如何在 Postgres 中解决这个问题?

【问题讨论】:

    标签: postgresql pagination


    【解决方案1】:
    SELECT * FROM events 
      WHERE created >= $<after> and (id >= $<id> OR created > $<after>)
      ORDER BY created ASC ,id ASC LIMIT 10
    

    这样每个时间戳值的事件将按 id 排序。你可以在任何地方拆分页面。

    你也可以这样说:

    SELECT * FROM events 
      WHERE (created,id) >= ($<after>,$<id>)
      ORDER BY created ASC ,id ASC LIMIT 10
    

    对我来说,这会产生一个更好的计划。

    (created,id) 上的索引对性能的帮助最大,但对于 在很多情况下,created 上的索引就足够了。

    【讨论】:

      【解决方案2】:

      首先,正如您所说,您应该强制执行总排序。由于您主要关心的是created,因此您应该从它开始。 id 可能是二级排序,一个用户看不见的决胜局,只是确保排序是一致的。其次,您可以使用offset 子句来返回以后的结果,而不是乱用created 上的条件:

      SELECT * FROM events ORDER BY created ASC, id ASC LIMIT 10 OFFSET <10 * page number>
      -- Note that page number is zero based 
      

      【讨论】:

      • 关于在订购中包含id的部分是正确的。关于OFFSET 的部分应该去 - 这样分页效率低下,我认为 OP 想要避免它。
      猜你喜欢
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-13
      • 2012-12-24
      • 2011-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多