在PostgreSQL中使用“Cursors”进行分页

时间:2012-10-30 15:52:32

标签: postgresql pagination paginate

  

可能重复:
  How to provide an API client with 1,000,000 database results?

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

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

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

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

非常感谢!

2 个答案:

答案 0 :(得分:27)

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

它们不适用于具有高客户端数量的大型应用程序以及像基于Web的应用程序或Web API那样随机出现的客户端。我不建议在你的应用程序中使用游标,除非你有一个相当小的客户端数和非常高的请求率......在这种情况下,发送微小批量的行将是非常低效的,你应该考虑允许范围请求等。 / p>

游标有几个成本。如果光标不是WITH HOLD,则必须保持事务处于打开状态。打开事务可以防止autovacuum正常工作,导致表膨胀和其他问题。如果光标被声明为WITH HOLD并且事务未保持打开,则必须支付实现和存储可能较大的结果集的成本 - 至少,我认为这是保持游标的工作方式。替代方案同样糟糕,保持事务隐式打开,直到光标被销毁并阻止行被清除。

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

与具有限制和偏移的无状态连接池方法相比,管理有状态的基于游标的设置还存在复杂性和开销。您需要在超时后使应用程序到期游标,或者您在服务器上面临可能无限制的资源使用,并且您需要跟踪哪些连接具有哪些游标的哪些用户的游标....

一般而言,尽管效率非常低,LIMITOFFSET可能是更好的解决方案。 It can often be better to search the primary key rather than using OFFSET, though

顺便说一句,您正在查看PL / pgSQL中游标的文档。你希望normal SQL-level cursors完成这项工作。


  

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

  

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

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

  

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

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

答案 1 :(得分:1)

对于HTTP客户端,请勿使用游标实现分页。对于可伸缩性,您不希望服务器资源在请求之间捆绑。

相反,在查询中使用LIMIT和OFFSET;见LIMIT and OFFSET in the Pg docs

但请确保表格上的索引支持对此表单进行有效查询。

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