2009-10-06 14 views
5

¿Es posible tener salidas de PL/SQL en tiempo real? Tengo un paquete bastante grande que funciona durante más de una hora y me gustaría ver dónde está el paquete en un momento determinado.Tiene salidas PL/SQL en tiempo real

De todos modos, actualmente hago esto con una tabla de registro, que se llena con cientos de descripciones de registro por ejecución, solo tengo curiosidad si esto es posible.

Gracias!

Respuesta

8

No sé si esto es exactamente lo que quieres, pero yo uso dbms_application_info.set_module para ver dónde está mi paquete.

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

una consulta en v$session se mostrará la parte del procedimiento se está ejecutando.

+1

Elegido por simplicidad. – jonasespelita

4

puede usar autonomous transactions (como se sugiere en this SO por ejemplo).

Esto le permitiría escribir y confirmar en una tabla de registro sin comprometer la transacción principal. A continuación, podrá seguir lo que sucede en su secuencia de comandos principal mientras se está ejecutando (de paso, también le permitirá ajustar/sincronizar su lote).

+0

+1 También hay una buena descripción en "Oracle PL/SQLProgramming" de Feuerstein, que también está disponible en los libros de Google. – Thorsten

+0

¡Agradable! Aprendí algo nuevo hoy. :) – jonasespelita

8

Este es el tipo de cosas que utilizo (salida puede ser visto en la sesión v $ y 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 Gran ejemplo –

1

Uso DBMS_PIPE para escribir un mensaje a una tubería con nombre. En otra sesión, puede leer los mensajes de la tubería. Muy simple, funciona como un encanto!

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

Si su trabajo a ejecutar siempre está procesando un gran número de tareas de manera bastante uniforme de tamaño, es posible que la sesión longops una buena manera de monitorear el progreso del trabajo, así como lo que le permite estimar cuánto tiempo el trabajo se tomar para terminar.

DBMS_APPLICATION_INFO.set_session_longops

0

Si usted tiene acceso al shell del entorno PL/SQL puede llamar netcat:

COMENZAR run_shell ('eco " '|| || v_msg'" | nc' || v_host | | '' || v_port || '-w 5'); FIN;

/

v_host es un script en Python host que ejecute que lee datos de socket en el puerto v_port.

Utilicé este diseño cuando escribí aplogr para la supervisión de registros de shell y pl/sql.