继我之前的问题之后:
Using "Cursors" for paging in PostgreSQL
为 API 客户端提供 1,000,000 个数据库结果的好方法是什么?
我们目前正在使用 PostgreSQL。一些建议的方法:
- 使用 Cursors 进行分页
- 使用随机数进行分页(在每个查询中添加“GREATER THAN ORDER BY”)
- 使用 LIMIT 和 OFFSET 进行分页(对于非常大的数据集会分解)
- 将信息保存到一个文件中,让客户端下载
- 遍历结果,然后将数据 POST 到客户端服务器
- 仅将 key 返回给客户端,然后让客户端从 Amazon S3 等云文件中请求对象(仍然可能需要分页才能获取文件名)。
有什么是我没有想到的,它比这些选项中的任何一个都简单得愚蠢而且好得多?
最佳答案
该表有一个主键。好好利用它。
代替 LIMIT
和 OFFSET
,使用主键过滤器进行分页。您在评论中暗示了这一点:
Paging using random numbers ( Add "GREATER THAN ORDER BY " to each query )
但是您应该如何做并不是随机的。
SELECT * FROM big_table WHERE id > $1 ORDER BY id ASC LIMIT $2
允许客户端指定这两个参数,它看到的最后一个 ID 和要获取的记录数。您的 API 必须具有占位符、额外参数或替代调用以“获取 第一个 n 个 ID”,其中它从查询中省略了 WHERE
子句,但这是微不足道。
此方法将使用相当高效的索引扫描来按顺序获取记录,通常避免排序或需要遍历所有跳过的记录。客户端可以决定一次需要多少行。
此方法在一个关键方面不同于LIMIT
和OFFSET
方法:并发修改。如果您INSERT
到表中的键低于 某个客户端已经看到的键,这种方法根本不会改变其结果,而OFFSET
方法将重复一行。类似地,如果您DELETE
具有低于已见 ID 的行,此方法的结果将不会改变,而 OFFSET
将跳过未见行。不过,对于具有生成键的仅追加表没有区别。
如果您事先知道客户需要整个结果集,那么最有效的做法就是将整个结果集发送给他们,而无需任何分页业务。这就是我会使用游标的地方。从数据库中读取行,并以客户端接受它们的速度将它们发送给客户端。这个 API 需要限制客户端的速度,以避免后端负载过大;对于慢速客户端,我可能会切换到分页(如上所述)或将整个游标结果假脱机到一个临时文件并关闭数据库连接。
重要警告:
- 需要
UNIQUE
约束/UNIQUE
索引或PRIMARY KEY
才能可靠 - 限制/偏移的不同并发修改行为,见上文
关于api - 如何向 API 客户端提供 1,000,000 个数据库结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13144005/