2009-10-06 4 views
5

E 'possibile avere uscite da PL/SQL in tempo reale? Ho un pacchetto piuttosto grande che viene eseguito per più di un'ora e mi piacerebbe vedere dove si trova il pacchetto in un momento particolare.Hanno uscite PL/SQL in tempo reale

Ad ogni modo, attualmente lo faccio con una tabella di log, che viene riempita con centinaia di descrizioni di log per corsa, sono curioso di sapere se è possibile.

Grazie!

risposta

8

Non so se questo è esattamente quello che vuoi ma io uso dbms_application_info.set_module per vedere dove si trova il mio pacchetto.

dbms_application_info.set_module(module_name => 'Conversion job', 
           action_name => 'updating table_x'); 

una query su v$session vi mostrerà quale parte della procedura è in esecuzione.

+1

Scelti per semplicità. – jonasespelita

4

è possibile utilizzare autonomous transactions (come suggerito in this SO per esempio).

Ciò consentirebbe di scrivere e eseguire il commit in una tabella di registro senza eseguire la transazione principale. Sarai quindi in grado di seguire ciò che accade nel tuo script principale mentre è in esecuzione (incidentalmente, ti permetterà anche di sincronizzare il tuo batch).

+0

+1 C'è anche una buona descrizione in "Oracle PL/SQLProgramming" di Feuerstein, disponibile anche nei libri di Google. – Thorsten

+0

Bello! Ho imparato una cosa nuova oggi. :) – jonasespelita

8

Questo è il tipo di cosa che uso (uscita può essere visto in v $ session e V $ session_longops) ...

DECLARE 
    lv_module_name VARCHAR2(48); 
    lv_action_name VARCHAR2(32); 

    gc_MODULE CONSTANT VARCHAR2(48) := 'MY_PROC'; 

    -- For LONGOPS 
    lv_rindex BINARY_INTEGER; 
    lv_slno BINARY_INTEGER; 

    lc_OP_NAME CONSTANT VARCHAR2(64) := '['||gc_MODULE||']'; 
    lv_sofar NUMBER; 

    -- This is a guess as to the amount of work we will do 
    lv_totalwork NUMBER; 
    lc_TARGET_DESC CONSTANT VARCHAR2(64) := 'Tables'; 
    lc_UNITS CONSTANT VARCHAR2(64) := 'Rows'; 

    CURSOR tab_cur 
    IS 
     SELECT owner, table_name 
     FROM all_tables; 

BEGIN 
    <<initialisation>> 
    BEGIN 
     -- To preserve the calling stack, read the current module and action 
     DBMS_APPLICATION_INFO.READ_MODULE(module_name => lv_module_name 
             , action_name => lv_action_name); 

     -- Set our current module and action 
     DBMS_APPLICATION_INFO.SET_MODULE(module_name => gc_MODULE 
             , action_name => NULL); 
    END initialisation; 

    <<main>> 
    BEGIN 
     DBMS_APPLICATION_INFO.SET_ACTION(action_name => 'Part 01'); 
     NULL; 

     DBMS_APPLICATION_INFO.SET_ACTION(action_name => 'Part 02'); 
     FOR tab_rec IN tab_cur 
     LOOP 
     DBMS_APPLICATION_INFO.SET_CLIENT_INFO(client_info => 'Rows = ['||TO_CHAR(tab_cur%ROWCOUNT, '999,999,999')||']'); 
     NULL; 
     END LOOP; 

     DBMS_APPLICATION_INFO.SET_ACTION(action_name => 'Part 03'); 

     --Initialising longops 
     lv_rindex := DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS_NOHINT; 
     lv_sofar := 0; 
     lv_totalwork := 5000; -- This is a guess, but could be actual if the query is quick 

     FOR tab_rec IN tab_cur 
     LOOP 
     DBMS_APPLICATION_INFO.SET_CLIENT_INFO(client_info => 'Rows = ['||TO_CHAR(tab_cur%ROWCOUNT, '999,999,999')||']'); 

     lv_sofar := lv_sofar + 1; 

     -- Update our totalwork guess 
     IF lv_sofar > lv_totalwork 
     THEN 
      lv_totalwork := lv_totalwork + 500; 
     END IF; 

     DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(rindex  => lv_rindex 
                , slno  => lv_slno 
                , op_name  => lc_OP_NAME 
                , sofar  => lv_sofar 
                , totalwork => lv_totalwork 
                , target_desc => lc_TARGET_DESC 
                , units  => lc_UNITS 
               ); 
     END LOOP; 

     -- Clean up longops 
     DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(rindex  => lv_rindex 
               , slno  => lv_slno 
               , op_name  => lc_OP_NAME 
               , sofar  => lv_sofar 
               , totalwork => lv_sofar 
               , target_desc => lc_TARGET_DESC 
               , units  => lc_UNITS 
               ); 
    END main; 

    <<finalisation>> 
    BEGIN 
     -- Reset the module and action to the values that may have called us 
     DBMS_APPLICATION_INFO.SET_MODULE(module_name => lv_module_name 
             , action_name => lv_action_name); 

     -- Clear the client info, preventing any inter process confusion for anyone looking at it 
     DBMS_APPLICATION_INFO.SET_CLIENT_INFO(client_info => NULL); 
    END finalisation; 
END; 
/
+0

+1 Ottimo esempio –

1

Usa DBMS_PIPE Per scrivere un messaggio a una named pipe. In un'altra sessione puoi leggere i messaggi dalla pipe. Molto semplice, funziona come un fascino!

procedure sendmessage(p_pipename varchar2 
         ,p_message varchar2) is 
     s number(15); 
    begin 
     begin 
     sys.dbms_pipe.pack_message(p_message); 
     exception 
     when others then 
      sys.dbms_pipe.reset_buffer; 
     end; 

     s := sys.dbms_pipe.send_message(p_pipename, 0); 

     if s = 1 
     then 
     sys.dbms_pipe.purge(p_pipename); 
     end if; 
    end; 




function receivemessage(p_pipename varchar2 
          ,p_timeout integer) return varchar2 is 
     n number(15); 
     chr varchar2(200); 
    begin 
     n := sys.dbms_pipe.receive_message(p_pipename, p_timeout); 

     if n = 1 
     then 
     return null; 
     end if; 

     sys.dbms_pipe.unpack_message(chr); 
     return(chr); 
    end; 
1

Se il vostro lavoro a lungo in esecuzione sta elaborando un gran numero di compiti abbastanza dimensionate in modo uniforme, è possibile trovare la sessione longops un buon modo di monitorare l'avanzamento del processo, oltre a permettere di stimare quanto tempo il lavoro sarà prendere per finire.

DBMS_APPLICATION_INFO.set_session_longops

0

Se si ha accesso a sborsare da ambiente PL/SQL è possibile chiamare netcat:

BEGIN RUN_SHELL ('echo " '|| v_msg ||'" | nc' || v_host | | '' || v_port || '-w 5'); FINE;

/

v_host è uno script python host che esegue che legge i dati dal socket sulla porta v_port.

Ho usato questo disegno quando ho scritto aplogr per il monitoraggio dei registri shell e pl/sql.