Have PL/SQL Outputs in Real Time

前端 未结 6 1823
陌清茗
陌清茗 2021-01-03 02:37

Is it possible to have Outputs from PL/SQL in real time? I have a pretty huge package that runs for more than an hour and I\'d like to see where the package is at a particul

相关标签:
6条回答
  • 2021-01-03 02:40

    you could use autonomous transactions (as suggested in this SO for example).

    This would allow you to write and commit in a log table without commiting the main transaction. You would then be able to follow what happens in your main script while it is running (incidentally, it will also allow you to time/tune your batch).

    0 讨论(0)
  • 2021-01-03 02:41

    If your long-running job is processing a large number of fairly evenly sized tasks, you may find session longops a good way of monitoring the job progress, as well as allowing you to estimate how long the job will take to finish.

    DBMS_APPLICATION_INFO.set_session_longops

    0 讨论(0)
  • 2021-01-03 02:48

    Use DBMS_PIPE to write a message to a named pipe. In another session you can read the messages from the pipe. Very simple, works like a charm !

    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;
    
    0 讨论(0)
  • 2021-01-03 02:52

    I don't know if this is exactly what you want but I use dbms_application_info.set_module to see where my package is.

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

    A query on v$session will show you which part of the procedure is running.

    0 讨论(0)
  • 2021-01-03 03:02

    If you have access to shell from PL/SQL environment you can call netcat:

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

    /

    v_host is a host running python script that reads data from socket on port v_port.

    I used this design when I wrote aplogr for shell and pl/sql logs monitoring.

    0 讨论(0)
  • 2021-01-03 03:03

    This is the kind of thing I use (output can be seen in v$session and 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 讨论(0)
提交回复
热议问题