如何向客户端报告长时间运行的PostgreSQL函数的进度

10

我有一个C#客户端应用程序,使用Npgsql调用PostgreSQL 9.1.4中的plpgsql函数。该函数需要很长时间,我希望以某种方式向客户端报告进度。我该怎么做?

LISTEN / NOTIFY机制听起来非常完美,但整个过程都在事务内运行,而NOTIFY事件直到事务结束才发送,对我毫无用处。

我尝试的另一件事是RAISE NOTICE,我可以在客户端上处理它们,但即使那些通知似乎也会被缓冲一段时间并分批发送。这比没有好,但不是理想的。是否有任何方法可以“刷新”它们,以便立即将它们发送给客户端?

4个回答

10
除了@Pavel提到的RAISE NOTICE,在Pg中还有另一种经典技术用于监控查询进度。虽然它有点像hack,但效果非常好。
您可以利用序列的更改立即在任何地方可见这一事实来公开函数的进度。要么使用硬编码序列并确保不同时调用该函数,要么将进度监控序列名称传递给函数。
您的函数可以在每次迭代时调用nextval(seqname),感兴趣的人可以使用SELECT last_value FROM seqname从另一个会话中检查序列的状态。
您可以通过设置计数器使序列倒计时完成。
create sequence test maxvalue 2147483647 increment by -1;

在您的函数开始时调用setval('seqname', num_items)。然后每个nextval调用都会向零计数。顺便说一下,2147483647是maxint

不必多言,这种方法并不可移植,并且不能保证从序列中SELECT始终按此方式工作。然而,它确实很方便。


10

没有比RAISE NOTICE更好的了。

这些信号不会被缓冲,而且是异步的,你的应用程序可能存在通知处理问题。


在PostgreSQL 8.4及以上版本中,您还可以为RAISE NOTICE提供错误代码,这使得更容易区分进度消息和可能发出的其他通知。 - Craig Ringer
你说得对,事实证明NOTICE确实在被触发时被传递了,但是函数中出现了非常奇怪的减速,而当我直接运行相同的查询时却没有出现这种情况。我现在已经找到了一个解决方法。 - EM0
RAISE NOTICE 会有相对较大的开销 - 它是客户端和服务器之间的网络握手。我通常不会在每次迭代中都发出通知,但我会在每一千次迭代时发出通知。 - Pavel Stehule
1
我编写了一个计数器函数,用于长时间转换SQL函数 - 也许它对你有用 http://okbob.blogspot.cz/2010/11/new-version-of-pst-collection-is.html#links - Pavel Stehule

1
最简单的方法是将您的pgsql函数拆分为多个子函数,然后在应用程序中按顺序调用它们,在应用程序中管理事务范围。

谢谢,但在这种特殊情况下,我可以向你保证它并不简单。 :) 还有其他办法吗? - EM0
我想不出来,抱歉。 - mathieu

0

您还可以使用:

EXECUTE 'COPY (SELECT ''progress: ' || progress_variable || ''') TO ''d:\progress.txt''';

在你的函数内部将当前进度写入文本文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接