我正在制作一个基于 HTTP 的 API,它通过分页从 PostgreSQL 中获取许多行。在一般情况下,我通常通过天真的 OFFET
/LIMIT
子句来实现这种分页。但是,在这种情况下有一些特殊要求:
- 有很多行,所以我相信用户无法到达终点(想象一下 Twitter 时间轴)。
- 页面不必是随机访问的,但只能按顺序访问。
- API 将返回一个 URL,其中包含指向连续 block 页面的游标标记。
- 游标标记不必永久存在,而是存在一段时间。
- 其顺序经常波动(如 Reddit 排名),但连续游标应保持一致的顺序。
我怎样才能完成任务?我已准备好为此更改我的整个数据库架构!
最佳答案
假设波动的只是结果的顺序而不是行中的数据,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_ids 以减少存储需求和每个用户运行初始查询所需的时间。如果它们可以共享,请选择一个缓存窗口,例如 1 或 5 分钟,然后根据新请求为该时间段创建 cache_token,然后检查是否已经为该 token 计算了结果 ID。如果不是,请为该标记添加一个新行。您可能应该在检查/插入代码周围添加一个锁,以处理对新 token 的并发请求。
安排一个清除旧 token /结果的后台作业,并确保您的客户端代码可以处理与过期/无效 token 相关的任何错误。
甚至不要考虑为此使用真正的数据库游标。
将结果 ID 保留在 Redis 列表中是处理此问题的另一种方法(请参阅 LRANGE 命令),但如果您沿着这条路走下去,请注意过期和内存使用情况。您的 Redis 键将是 cursor_token,而 ID 将是列表的成员。
关于postgresql - 如何在网络中使用 PostgreSQL 获取连续列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7746920/