26

可能重复:
如何为 API 客户端提供 1,000,000 个数据库结果?

想知道游标的使用是使用 PostgreSQL 实现“分页”的好方法。

用例是我们希望向 API 客户端提供超过 100,000 行。我们认为实现这一点的一个好方法是允许客户端批量(页面)请求信息。客户端一次可以请求 100 行。我们将返回 100 行以及一个游标,然后当客户端准备好时,他们可以使用我们发送给他们的游标请求接下来的 100 行。

但是,我对游标的工作方式以及应该如何以及何时使用游标有点模糊:

  • 游标是否要求数据库连接保持打开状态?
  • 游标是否在事务中运行,锁定资源直到它们“关闭”?
  • 还有其他我不知道的“陷阱”吗?
  • 是否有另一种更好的方法来处理这种情况?

非常感谢!

4

2 回答 2

37

在处理大型数据集的小型 Intranet 应用程序中,游标是分页的合理选择,但您需要准备好在超时后丢弃它们。用户喜欢闲逛、去吃午饭、去度假两周等,然后让他们的应用程序继续运行。如果它是一个基于网络的应用程序,甚至还有什么是“正在运行”以及如何判断用户是否还在附近的问题。

它们不适合具有大量客户端的大型应用程序以及几乎随机进出的客户端,例如基于 Web 的应用程序或 Web API。我不建议在您的应用程序中使用游标,除非您的客户端数量相当少且请求率非常高......在这种情况下发送小批量的行将非常低效,您应该考虑允许范围请求等。

光标有几个成本。如果光标不是WITH HOLD,您必须保持事务打开。打开的事务可能会阻止 autovacuum 正常工作,从而导致表膨胀和其他问题。如果声明了游标WITH HOLD并且事务未保持打开状态,则您必须支付实现和存储可能很大的结果集的成本——至少,我认为保持游标是这样工作的。另一种方法同样糟糕,保持事务隐式打开直到游标被破坏并防止行被清理。

此外,如果您使用游标,则无法将连接交回连接池。每个客户端需要一个连接。这意味着更多的后端资源仅用于维护会话状态,并为您可以使用基于游标的方法处理的客户端数量设置了一个非常真实的上限。

与具有限制和偏移的无状态连接池方法相比,管理有状态的、基于游标的设置也存在复杂性和开销。您需要让您的应用程序在超时后使游标过期,否则您将面临服务器上潜在的无限资源使用,并且您需要跟踪哪些连接具有哪些游标针对哪些结果集针对哪些用户......

一般来说,尽管它可能效率很低,但LIMIT可能OFFSET是更好的解决方案。不过,搜索主键通常比使用 更好OFFSET

顺便说一句,您正在查看 PL/pgSQL 中游标的文档。您需要此作业的普通 SQL 级游标


游标是否要求数据库连接保持打开状态?

是的。

游标是否在事务中运行,锁定资源直到它们“关闭”?

是的,除非它们是WITH HOLD,在这种情况下它们会消耗其他数据库资源。

还有其他我不知道的“陷阱”吗?

是的,正如上面应该解释的那样。

于 2012-10-30T23:41:48.623 回答
0

对于 HTTP 客户端,不要使用游标来实现分页。为了可扩展性,您不希望服务器资源在请求之间被占用。

相反,请在查询中使用 LIMIT 和 OFFSET;请参阅LIMITOFFSET在 Pg 文档中。

但请确保您的表上的索引将支持这种形式的高效查询。

设计一个 RESTful API,以便客户端可以调用“next_url”(也在响应中传递)来获取下一组行。

于 2012-10-30T16:00:31.457 回答