在postgresql有线协议中,如何从部分执行的选择中获取ReadyForQuery?

时间:2014-09-17 21:48:45

标签: node.js postgresql postgresql-9.3

我正在尝试使用`node-pg-cursor'来调试问题。 node.js中的模块对postgresql服务器(版本9.3)

该模块允许在选择中顺序读取N行,并通过发送

工作
cur.read(N): 'Execute' on portal=unnamed, rows=N

此命令最多可提取N行,我们可以继续逐步提取行,直到我们收到的结尾

CommandComplete
ReadyForQuery

现在我的问题是我想在获取所有行并到达Execute序列的末尾之前摆脱扩展命令:我想逐步获取N行,N行,N行,...和at一点决定我有足够的。

当我这样做时(通过Execute停止提取),查询似乎永远不会到达CommandComplete或ReadyForQuery。这似乎是正常的,因为没有任何东西告诉扩展查询我永远不会再次询问它的行。

除了关闭连接外,是否有命令在没有从门户网站获取所有行的情况下到达CommandComplete或ReadyForQuery?

我尝试发送Close并收到CloseComplete,但它没有转到ReadyForQuery。

如果我通过在协议上发送垃圾来强制使用ErrorResponse,我会到达ReadyForQuery,但这看起来不是很干净......

2 个答案:

答案 0 :(得分:3)

我认为你指的是这个,in the documentation

  

如果Execute在完成门户网站的执行之前终止(由于达到非零结果行计数),它将发送PortalSuspended消息;此消息的外观告诉前端应该针对同一门户发出另一个Execute来完成操作。在门户网站执行完成之前,不会发送指示源SQL命令完成的CommandComplete消息。因此,Execute阶段始终通过出现其中一条消息而终止:CommandCompleteEmptyQueryResponse(如果门户网站是从空查询字符串创建的),{{1} },或ErrorResponse

据推测,您正在获取PortalSuspended,并且您希望丢弃门户网站而不再执行任何更多操作或消耗更多结果。

如果是这样,我认为您只需发送PortalSuspended消息:

  

在完成每一系列扩展查询消息后,前端应发出同步消息。如果不在BEGIN / COMMIT事务块中,则此无参数消息会导致后端关闭当前事务(“close”表示如果没有错误则提交,或者如果错误则回滚)。然后发出ReadyForQuery响应。

您可能希望首先针对门户网站发布Sync

  

Close消息关闭现有的预准备语句或门户并释放资源。

所以我认为你需要做的是,在消息流方面:

  • Close
  • Parse一个命名门户网站
  • Bind
  • 循环:
    • Describe使用rowcount限制来获取某些行
    • 如果不再需要行;然后
      • Execute门户网站
      • 突破循环
    • 如果收到Close
      • 突破循环
  • CommandComplete
  • 等待Sync

答案 1 :(得分:1)

如果您的驱动程序是libpq包装器,听起来您可能希望使用the asynchronous query processing API。如果它是本机实现,libpq的源代码可能会为您提供线索。

总的来说,看起来您需要使用新连接取消查询,然后继续使用输入,直到缓冲区为空。然而,你会收到很多结果数据被缓冲,然后是一条错误消息,表明查询被取消了(如果它在你取消之前没有缓冲所有输出),最后是ReadyForQuery。

我引用the libpq manual

  

使用PQsendQuery / PQgetResult的客户端也可以尝试取消仍由服务器处理的命令; see Section 31.6。但无论PQcancel的返回值如何,应用程序都必须使用PQgetResult继续正常的结果读取序列。成功取消将导致命令更快地终止。

系统通常具有相当大的TCP发送缓冲区,并且它们通常是动态的。请参阅Linux's tcp(7)SO_SNDBUF的{​​{1}}选项等等。因此,在PostgreSQL服务器写入套接字时阻塞之前,可能会缓冲大量数据。 PostgreSQL不提供发送缓冲区大小的每个连接控制,甚至不提供全局配置选项;您必须在操作系统级别上执行此操作。 (也就是说,如果你愿意的话,修补PostgreSQL以设置setsockopt(2)setsockopt的发送缓冲区大小是微不足道的。

取消查询时,PostgreSQL不能只刷新输出缓冲区。即使这样做是安全的并且平台支持它,Pg也不确定缓冲区是否已清空先前查询和其他相关消息的结果,因为您可能已经对多个查询进行了调整。

所以你真正要做的就是减少TCP输出缓冲区的最大大小。这将减少您必须阅读和丢弃的数据量,但它可能会影响发送批量数据的其他查询的性能。

我建议你不要试图运行查询并在你看到足够的时候取消它,而是建议批量读取行,当你消耗了当前的批量时请求新批次。您可以使用协议级游标执行此操作。这样,您就可以控制服务器排队的数据量,并且您不必混淆缓冲区大小。您可能已经这样做 - 使用命名门户网站,并发送具有最大行数的SO_SENDBUF,等待Execute说明还有更多行要读取。