2009-10-06 24 views
5

Czy możliwe jest posiadanie wyjść z PL/SQL w czasie rzeczywistym? Mam bardzo duży pakiet, który działa przez ponad godzinę i chciałbym zobaczyć, gdzie jest paczka w określonym czasie.Masz wyjścia PL/SQL w czasie rzeczywistym

Tak czy inaczej, obecnie robię to z tabelą dziennika, która wypełnia się setkami opisów logów na przebieg, jestem po prostu ciekawy, czy to jest możliwe.

Dzięki!

Odpowiedz

8

Nie wiem, czy to jest dokładnie to, czego chcesz, ale używam dbms_application_info.set_module, aby zobaczyć, gdzie jest mój pakiet.

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

Zapytanie o v$session pokaże, jaka część procedury jest uruchomiony.

+1

Wybrane dla uproszczenia. – jonasespelita

4

można użyć autonomous transactions (zgodnie z sugestią na przykład w this SO).

Umożliwia to zapisywanie i zatwierdzanie w tabeli dziennika bez konieczności wykonywania głównej transakcji. Będziesz wtedy mógł śledzić, co dzieje się w głównym skrypcie, gdy jest on uruchomiony (nawiasem mówiąc, pozwoli ci to również na czas/dostrojenie twojej partii).

+0

+1 Istnieje również dobry opis w "Oracle PL/SQLProgramming" Feuersteina, który jest również dostępny w książkach Google. – Thorsten

+0

Nice! Dziś nauczyłem się czegoś nowego. :) – jonasespelita

8

Jest to rodzaj rzeczy używam (wyjście widać v $ sesji i 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 Świetny przykład –

1

Korzystanie DBMS_PIPE napisać wiadomość do nazwanego potoku. W kolejnej sesji możesz czytać wiadomości z potoku. Bardzo proste, działa jak urok!

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

Jeśli długotrwała praca przetwarza dużą ilość dość równomiernie których wielkość zadań, można znaleźć sesję longops dobry sposób monitorowania postępu pracy, a także pozwala oszacować, jak długo zadanie będzie zabierz się do końca.

DBMS_APPLICATION_INFO.set_session_longops

0

Jeśli masz dostęp do powłoki z PL/SQL środowiska można wywołać netcat:

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

/

v_host jest gospodarzem uruchomiony skrypt Pythona, który odczytuje dane z gniazda na porcie v_port.

Użyłem tego projektu, gdy napisałem aplogr dla monitorowania logów powłoki i pl/sql.

Powiązane problemy