Notify bei einer Set Returning Function

Hallo,

ich habe folgendes Szenario: eine Funktion in PL/pgSQL führt ziemlich umfangreiche Operationen an der Datenbank durch (Laufzeit ca. 5 - 10 min). Jetzt möchte ich die Funktion von einem Java-Client aus anstoßen und damit der Benutzer nicht einschläft oder die Berechnung abbricht, weil sich scheinbar nichts tut, den Fortschritt anzeigen.

Dazu sendet die PL/pgSQL-Funktion nach jedem bearbeiteten Datensatz noch eine Nachricht per pg_notify(). Im Java-Client gibt es einen Hintergrundprozess, der diese Nachrichten abfängt und auf der Oberfläche signalisiert. Im Java-Client funktioniert alles ganz wunderbar: wenn ich die entsprechende Nachricht von der Konsole per Hand sende, erscheint im Client mit einer Verzögerung < 1/2 Sekunde die entsprechende Nachricht.

Wenn ich jedoch die Funktion anstoße, tut sich 5 Minuten nichts auf der Oberfläche und erst wenn die Funktion fertig ist, erscheinen alle Nachrichten auf einen Schlag. Sende ich während der Laufzeit der Funktion von Hand weitere die Nachricht, erscheinen die von Hand gesendeten Nachrichten sofort. Die von der Funktion gesendeten jedoch nicht. Diese erscheinen erst auf einen Schlag am Ende.

Es sieht für mich also so aus, als wenn der Server die Nachrichten der PL/pgSQL-Funktion erst sammelt und dann am Schluss im Ganzen versendet.

Testweise hänge ich im Java-Client an jede empfangene Nachricht einen Zeitstempel an. Alle aufgelaufenen Nachrichten von der Funktion tragen nach Abschluss der Funktion den selben Zeitstempel: nämlich den, wenn die Funktion endet. Die von Hand gesendeten Nachrichten tragen den Zeitstempel des Zeitpunktes, an dem ich die Nachricht versendet habe.

Weiß jemand woran das liegt oder kann mir jemand Tipps geben, an welcher Stelle ich suchen soll, wodurch es zu dieser Verzögerung kommt?

Ich fürchte ich habe die Lösung gefunden: die Notify-Meldungen werden erst abgesetzt, wenn die Transaktion erfolgreich beendet wurde… :frowning:
Leider habe ich die Dokumentation zu flüchtig gelesen…

Ich weiß nicht, ob Du RAISE NOTICE - Meldungen abfangen kannst, folgendes tut aber erst einmal in der lang lauenden Funktion die entsprechenden Meldungen sofort ausgeben:

test=*# create or replace function long_running() returns bool as $$begin raise notice '1'; perform pg_sleep(1); raise notice '2'; perform pg_sleep(1); raise notice '3'; return true; end;$$language plpgsql;
CREATE FUNCTION
Time: 0,496 ms
test=*# select * from long_running();
NOTICE:  1
NOTICE:  2
NOTICE:  3
 long_running
--------------
 t
(1 row)

Darüber denke ich auch gerade nach. Ich habe schon mehrmals festgestellt, dass RAISE NOTICE-Meldungen auch aus einer Transaktion heraus kommen. Ich werde das mal verfolgen und darüber berichten.
Danke für den Tipp.

Btw.: gibt es eigentlich einen Grund, warum NOTIFY-Meldungen erst am Ende der Transaktion gesendet werden?

Ja, steht in der Doku. “This is appropriate, since if the transaction is aborted, all the commands within it have had no effect, including NOTIFY.”

Okay, ich hatte meine letzte Frage nicht korrekt formuliert: die eigentlich Frage hätte lauten müssen, warum NOTIFY-Meldungen nur bei einem COMMIT gesendet werden und nicht bei einem ROLLBACK?
Den von Dir genannten Hinweis hatte ich ja gelesen.

Warum sollte bei einem ROLLBACK was gesendet werden? “Es ist grade nichts passiert?” :wink:

Ich will ja über NOTICE den Benutzer darüber informieren, dass gerade etwas passiert und wie weit die Funktion gerade ist.
Wie gesagt: die Funktion braucht schon ein paar Minuten und manche User fangen bekanntlich schon nach wenigen Sekunden an, wie wild auf der Tastatur rum zu hämmern, wenn sich scheinbar nichts tut…

Ich habe es jetzt mit RAISE NOTICE gemacht. Damit funktioniert es.