15

跟进我之前的问题:

在 PostgreSQL 中使用“游标”进行分页

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

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

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

我没有想到这比这些选项中的任何一个都简单得​​多并且更好吗?

4

2 回答 2

32

该表有一个主键。好好利用它。

代替LIMITand OFFSET,使用主键上的过滤器进行分页。您在评论中暗示了这一点:

使用随机数进行分页(在每个查询中添加“GREATER THAN ORDER BY”)

但是你应该怎么做并不是随机的。

SELECT * FROM big_table WHERE id > $1 ORDER BY id ASC LIMIT $2

允许客户端指定两个参数,它看到的最后一个 ID 和要获取的记录数。您的 API 必须有一个占位符、额外参数或替代调用“获取n 个 ID”,其中省略了WHERE查询中的子句,但这很简单。

这种方法将使用相当有效的索引扫描来按顺序获取记录,通常避免排序或遍历所有跳过的记录的需要。客户端可以决定一次需要多少行。

这种方法在一个关键方面与LIMITand方法不同OFFSET:并发修改。如果您使用低于某些客户已经看到的键INSERT的键进入表,这种方法根本不会改变其结果,而该方法将重复一行。同样,如果您的行 ID 低于已见过的 ID,则此方法的结果不会改变,而会跳过未见过的行。不过,生成键的仅追加表没有区别。OFFSETDELETEOFFSET

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

重要警告

  • 需要UNIQUE约束/UNIQUE索引或PRIMARY KEY可靠
  • 限制/偏移的不同并发修改行为,见上文
于 2012-10-30T23:57:18.523 回答
1

让 API 接受开始的偏移量和要返回的记录数。这是一种分页,客户端可以确定在一个页面请求中返回多少条记录。API 还应该返回查询可能的记录总数,以便客户端知道有多少“页面”,或者当返回的记录数为零或小于要求的记录。您可以通过在 SELECT 语句中使用 OFFSET 子句(从哪个记录开始检索)和 LIMIT 子句(要返回的记录数)在 PostgresSQL 查询中控制这一点。

于 2012-10-30T17:12:53.490 回答