我正在尝试使用`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,但这看起来不是很干净......
答案 0 :(得分:3)
我认为你指的是这个,in the documentation:
如果
Execute
在完成门户网站的执行之前终止(由于达到非零结果行计数),它将发送PortalSuspended
消息;此消息的外观告诉前端应该针对同一门户发出另一个Execute来完成操作。在门户网站执行完成之前,不会发送指示源SQL命令完成的CommandComplete
消息。因此,Execute
阶段始终通过出现其中一条消息而终止:CommandComplete
,EmptyQueryResponse
(如果门户网站是从空查询字符串创建的),{{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
说明还有更多行要读取。