如何为API客户端提供1,000,000个数据库结果?

Chr*_*row 12 api postgresql pagination distributed-computing

跟进我之前的问题:

在PostgreSQL中使用"Cursors"进行分页

为API客户端提供1,000,000个数据库结果的好方法是什么?

我们目前正在使用PostgreSQL.一些建议的方法:

  • 使用游标进行分页
  • 使用随机数进行分页(为每个查询添加"GREATER THAN BYDER BY")
  • 使用LIMIT和OFFSET进行分页(针对非常大的数据集进行分解)
  • 将信息保存到文件中,然后让客户端下载它
  • 迭代结果,然后将数据POST到客户端服务器
  • 仅返回客户端的密钥,然后让客户端从Amazon S3等云文件中请求对象(仍然可能需要分页才能获取文件名).

我没有想到的是愚蠢的简单和比任何这些选项更好的方式?

Cra*_*ger 28

该表有一个主键.利用它.

而不是LIMITOFFSET,使用主键上的过滤器进行分页.你用你的评论暗示了这一点:

Paging using random numbers ( Add "GREATER THAN ORDER BY " to each query )

but there's nothing random about how you should do it.

SELECT * FROM big_table WHERE id > $1 ORDER BY id ASC LIMIT $2
Run Code Online (Sandbox Code Playgroud)

Allow the client to specify both parameters, the last ID it saw and the number of records to fetch. Your API will have to either have a placeholder, extra parameter, or alternate call for "fetch the first n IDs" where it omits the WHERE clause from the query, but that's trivial.

This approach will use a fairly efficient index scan to get the records in order, generally avoiding a sort or the need to iterate through all the skipped records. The client can decide how many rows it wants at once.

这种方法不同于LIMITOFFSET在一个关键途径办法:并发修改.如果您INSERT使用低于某个客户端已经看到的密钥的密钥进入表中,则此方法将根本不会更改其结果,而该OFFSET方法将重复一行.类似地,如果您DELETE的行具有低于已经看到的ID,则此方法的结果将不会更改,而OFFSET将跳过看不见的行.但是,仅使用生成密钥的附加表没有区别.

如果您事先知道客户端需要整个结果集,那么最有效的方法就是将整个结果集发送给它们,而不是这个分页业务.这就是我使用游标.从数据库中读取行并将其发送到客户端,只要客户端接受它们即可.此API需要设置限制客户端允许的速度以避免过多的后端负载; 对于慢速客户端,我可能会切换到分页(如上所述)或将整个游标结果假脱机到临时文件并关闭数据库连接.

重要提示:

  • 需要UNIQUE约束/ UNIQUE索引或是PRIMARY KEY可靠的
  • 限制/偏移的不同并发修改行为,见上文