2012-08-15 6 views
9

Ho un'applicazione client C# che utilizza Npgsql per chiamare una funzione plpgsql in PostgreSQL 9.1.4. La funzione richiede molto tempo e vorrei segnalare i progressi al cliente in qualche modo. Come dovrei farlo?Come segnalare l'avanzamento dalla funzione PostgreSQL di lunga esecuzione al client

Il meccanismo LISTEN/NOTIFY è perfetto per questo, tranne per il fatto che l'intera operazione viene eseguita all'interno di una transazione e gli eventi NOTIFY non vengono inviati fino alla fine della transazione, il che è inutile per me.

L'altra cosa che ho provato è RAISE AVVISO, che posso elaborare sul client, ma anche quelle notifiche sembrano essere memorizzate nel buffer per un po 'e inviate in batch. È meglio di niente, ma non è l'ideale. C'è un modo in cui posso "svuotarli", quindi vengono inviati immediatamente al cliente?

risposta

6

Non c'è niente di meglio di AUMENTARE AVVISO.

Questi segnali non vengono memorizzati nel buffer e sono asincroni: è probabile che si abbia un problema nell'elaborazione delle notifiche nell'applicazione.

+0

Con PostgreSQL 8.4 e versioni successive è anche possibile fornire un codice di errore a AVVISO RAISE, che rende più facile rilevare la differenza tra i messaggi di stato e altre notifiche che potrebbero essere emesse. –

+0

Hai ragione, si scopre che gli AVVISI * erano * consegnati mentre venivano sollevati, ma c'era un rallentamento molto strano nella funzione, che non si verificava quando eseguivo direttamente la stessa query. Ho trovato una soluzione alternativa per ora. – EM0

+0

AVVISO RAISE ha un relativo overhead significativo: è l'handshake di rete tra client e server. Di solito non alzo avviso ogni iterazione, ma noto ogni mille iterazioni. –

1

Il modo più semplice sarebbe dividere la funzione pgsql in più funzioni secondarie, anziché chiamarle in sequenza, lato applicazione, gestendo l'ambito della transazione nell'applicazione.

+0

Grazie, ma in questo caso particolare non sarebbe semplice, posso assicurarti. :) Altri modi? – EM0

+0

Non che io possa pensare, mi spiace – mathieu

7

Oltre all'eccellente punto @ Pavel su RAISE NOTICE, esiste un'altra tecnica classica utilizzata per monitorare l'avanzamento della query in Pg. È un po 'un trucco, ma è piuttosto efficace.

È possibile sfruttare il fatto che le modifiche alle sequenze sono immediatamente visibili ovunque per esporre l'avanzamento di una funzione all'esterno. Utilizzare una sequenza codificata e assicurarsi che la funzione non venga chiamata contemporaneamente o passare il nome della sequenza di monitoraggio dell'avanzamento alla funzione.

La funzione può chiamare nextval(seqname) ad ogni iterazione e le parti interessate possono esaminare lo stato della sequenza con SELECT last_value FROM seqname da un'altra sessione.

è possibile effettuare la sequenza di un conto alla rovescia fino al completamento impostandolo con

create sequence test maxvalue 2147483647 increment by -1; 

e chiamando setval('seqname', num_items) all'inizio della vostra funzione. Avrà quindi un conto alla rovescia verso zero con ciascuna chiamata nextval. 2147483647 è maxint, a proposito.

Inutile dire che questo non è portatile, e non c'è alcuna garanzia che SELECT da una sequenza funzionerà sempre in questo modo. È dannatamente comodo, però.

+0

+ 1 bel trucco, grazie. – EM0

0

È anche possibile utilizzare:

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

all'interno vostra funzione di scrivere il progresso corrente in un file di testo.