用PostgreSQL在网络上获取连续列表的最佳方法

问题描述 投票:8回答:2

我正在通过HTTP创建一个API,该API通过分页从PostgreSQL中获取许多行。在通常情况下,我通常通过幼稚的OFFET / LIMIT子句实现这种分页。但是,在这种情况下有一些特殊要求:

  • 有很多行,所以我相信用户无法到达结尾(想象一下Twitter时间轴)。
  • 不必随机访问页面,而只能按顺序访问。
  • API将返回一个URL,该URL包含一个指向连续块页面的游标令牌。
  • 游标令牌不必永久存在,而是需要一段时间。
  • 其顺序经常波动(如Reddit排名),但是连续的光标应保持其一致的顺序。

我如何完成任务?我准备为此更改整个数据库架构!

http postgresql pagination cursor continuous
2个回答
6
投票

假设只是结果的顺序波动,而不是行中的数据波动,Fredrik的回答很有意义。但是,我建议添加以下内容:

  • 使用array类型将id列表存储在postgresql表中,而不是存储在内存中。在内存中执行此操作,除非您小心地使用具有自动到期和内存限制的redis之类的东西,否则将使自己很容易受到DOS内存消耗的攻击。我想它看起来像这样:

    create table foo_paging_cursor (
      cursor_token ..., -- probably a uuid is best or timestamp (see below)
      result_ids integer[], -- or text[] if you have non-integer ids
      expiry_time TIMESTAMP
    );
    
  • 您需要确定是否可以在用户之间共享cursor_token和result_id,以减少存储需求以及每个用户运行初始查询所需的时间。如果可以共享它们,请选择一个缓存窗口,例如1或5分钟,然后在新请求时为该时间段创建cache_token,然后检查是否已经为该令牌计算了结果ID。如果没有,请为该令牌添加新行。您可能应该在检查/插入代码周围添加一个锁,以处理对新令牌的并发请求。

  • 具有排定的后台作业,该作业将清除旧令牌/结果,并确保您的客户端代码可以处理与过期/无效令牌有关的任何错误。

甚至不考虑为此使用真正的数据库游标。

将结果ID保留在Redis列表中是另一种处理此问题的方法(请参见LRANGE命令),但是如果沿着该路径使用,请注意到期和内存使用情况。您的Redis键将是cursor_token,而ID将是列表的成员。


1
投票

我对PostgreSQL完全不了解,但是我是一个相当不错的SQL Server开发人员,所以无论如何我都想尝试一下:)您希望用户每次会话最多浏览多少行/页?例如,如果您希望用户为每个会话(每个页面包含50行)最多翻阅10个页面,则可以使用该最大值,并设置网络服务,以便在用户请求第一页时缓存10 * 50行(或者仅是行的Id:s,取决于您获得多少内存/同时用户)。

这肯定会以多种方式帮助您加快Web服务的速度。而且很容易实现。因此:

    [当用户从第1页请求数据时。运行查询(完成排序,联接检查等),将所有id:s存储到数组中(但最多500个id)。返回与数组中位置0-9处的id:s对应的数据行。
  • 当用户请求第2-10页时。返回在数组位置(page-1)* 50-(page)* 50-1对应于数组中id:s的数据行。
  • 您还可以增加数字,一个500 int:s的数组仅会占用2K的内存,但这还取决于您希望初始查询/响应的速度。

我在实时网站上使用了类似的技术,当用户继续浏览第10页时,我只是切换到查询。我想另一个解决方案是继续扩展/填充数组。 (再次运行查询,但不包括已经包含的ID:S)。

无论如何,希望这会有所帮助!

© www.soinside.com 2019 - 2024. All rights reserved.