实时拥有PL / SQL输出

时间:2009-10-06 06:41:15

标签: sql oracle plsql

是否可以实时输出PL / SQL的输出?我有一个非常庞大的包,运行了一个多小时,我想看看包裹在特定时间的位置。

无论如何,我目前使用日志表执行此操作,每次运行时会填充数百个日志说明,我只是好奇这是否可行。

谢谢!

5 个答案:

答案 0 :(得分:8)

我不知道这是否正是您想要的,但我使用dbms_application_info.set_module来查看我的包的位置。

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

v$session上的查询将显示该程序的哪个部分正在运行。

答案 1 :(得分:8)

这是我使用的东西(输出可以在v $ session和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;
/

答案 2 :(得分:4)

您可以使用autonomous transactions(例如this SO中建议的那样)。

这将允许您在不提交主事务的情况下在日志表中编写和提交。然后,您可以跟踪主脚本运行时发生的情况(顺便提一下,它还允许您对批处理进行时间/调整)。

答案 3 :(得分:1)

使用DBMS_PIPE将消息写入命名管道。在另一个会话中,您可以从管道中读取消息。很简单,就像一个魅力!

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;

答案 4 :(得分:1)

如果长时间运行的作业正在处理大量相当均匀的任务,您可能会发现会话longops是监视作业进度的好方法,并且允许您估计作业完成所需的时间。

DBMS_APPLICATION_INFO.set_session_longops