Иметь выходы PL / SQL в реальном времени - PullRequest
5 голосов
/ 06 октября 2009

Возможно ли иметь выходы из PL / SQL в реальном времени? У меня довольно большой пакет, который работает более часа, и я хотел бы увидеть, где пакет находится в определенное время.

В любом случае, я сейчас делаю это с помощью таблицы журналов, которая заполняется сотнями описаний журналов за цикл, мне просто любопытно, возможно ли это.

Спасибо!

Ответы [ 6 ]

8 голосов
/ 06 октября 2009

Я использую такие вещи (вывод можно увидеть в 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;
/
8 голосов
/ 06 октября 2009

Я не знаю, если это именно то, что вы хотите, но я использую dbms_application_info.set_module, чтобы увидеть, где находится мой пакет.

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

Запрос на v$session покажет вам, какая часть процедуры выполняется.

4 голосов
/ 06 октября 2009

вы можете использовать автономные транзакции (как предложено в в этом SO , например).

Это позволит вам записывать и фиксировать в таблице журнала без фиксации основной транзакции. После этого вы сможете следить за тем, что происходит с вашим основным сценарием во время его работы (кстати, это также позволит вам синхронизировать / настраивать ваш пакет).

1 голос
/ 05 сентября 2012

Если ваше долгосрочное задание обрабатывает большое количество задач довольно равномерного размера, вы можете найти длинные сеансы в качестве хорошего способа наблюдения за ходом выполнения задания, а также оценки того, сколько времени займет выполнение задания.

DBMS_APPLICATION_INFO.set_session_longops

1 голос
/ 15 апреля 2010

Используйте 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;
0 голосов
/ 27 ноября 2017

Если у вас есть доступ к оболочке из среды PL / SQL, вы можете вызвать netcat:

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

/

v_host - хост, на котором выполняется скрипт Python, который считывает данные из сокета на порту v_port.

Я использовал этот дизайн, когда писал aplogr для мониторинга журналов оболочки и pl / sql.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...