2009-09-24 8 views
33

Mam skrypt SQL, który jest wywoływany z poziomu skryptu powłoki i trwa długo. Obecnie zawiera on wypowiedzi w różnych punktach: dbms_output.put_line. Dane wyjściowe z tych instrukcji drukowania pojawiają się w plikach dziennika, ale tylko po zakończeniu skryptu.Czy istnieje sposób na wypróżnienie wyjścia z PL/SQL w Oracle?

Czy istnieje jakiś sposób, aby upewnić się, że wyjście pojawia się w pliku dziennika jako skrypt jest uruchomiony?

Odpowiedz

46

Niezupełnie. Sposób działania DBMS_OUTPUT jest następujący: Twój blok PL/SQL jest wykonywany na serwerze bazy danych bez interakcji z klientem. Tak więc, gdy wywołasz PUT_LINE, po prostu umieszczasz ten tekst w buforze w pamięci na serwerze. Kiedy twój blok PL/SQL się zakończy, kontrola jest zwracana do klienta (w tym przypadku zakładam SQLPlus); w tym momencie klient pobiera tekst z bufora, wywołując GET_LINE i wyświetla go.

Tak więc jedynym sposobem, w jaki można częściej wyświetlać dane wyjściowe w pliku dziennika, jest rozbicie dużego bloku PL/SQL na wiele mniejszych bloków, więc kontrola jest częściej zwracana klientowi. To może nie być praktyczne w zależności od tego, co robi twój kod.

Inne alternatywy to użycie UTL_FILE do zapisu w pliku tekstowym, który można przepłukać w dowolnym momencie lub użyć procedury autonomicznej transakcji do wstawienia instrukcji debugowania do tabeli bazy danych i zatwierdzenia po każdym z nich.

4

Bufor o numerze DBMS_OUTPUT jest odczytywany po wywołaniu procedury DBMS_OUTPUT.get_line. Jeśli twoją aplikacją kliencką jest SQL * Plus, oznacza to, że zostanie ona opróżniona dopiero po zakończeniu procedury.

Możesz zastosować metodę opisaną w this SO, aby zapisać do pliku bufor DBMS_OUTPUT.

6

dwie alternatywy:

  1. można wstawić swoje dane logowania w tabeli logowania przy użyciu autonomicznej transakcji. Możesz wysłać zapytanie do tej tabeli rejestrowania w innej sesji dewelopera SQLPLUS/Toad/sql etc ... .... Musisz użyć autonomicznej transakcji, aby umożliwić zatwierdzenie rejestrowania bez zakłócania obsługi transakcji w głównym skrypcie sql.

  2. Inną alternatywą jest użycie potokowym funkcję, która zwraca swoje dane logowania. Zobacz tutaj na przykład: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html Kiedy używasz potokowej funkcji, nie musisz używać innej SQLPLUS/Toad/sql developer etc ... session.

3

Jeśli jest to możliwe, należy zastąpić wywołania dbms_output.put_line przez własną funkcję.

Oto kod dla tej funkcji WRITE_LOG - jeśli chcesz mieć możliwość wyboru pomiędzy 2 rozwiązań rejestrowania:

logów zapisu do tabeli w autonomous transaction

CREATE OR REPLACE PROCEDURE to_dbg_table(p_log varchar2) 
    -- table mode: 
    -- requires 
    -- CREATE TABLE dbg (u varchar2(200) --- username 
    --     , d timestamp  --- date 
    --     , l varchar2(4000) --- log 
    --); 
AS 
    pragma autonomous_transaction; 
BEGIN 
    insert into dbg(u, d, l) values (user, sysdate, p_log); 
    commit; 
END to_dbg_table; 
/

lub bezpośrednio na serwerze bazy danych, który hostuje bazę danych

używa wówczas procedura Oracle directoryTMP_DIR

CREATE OR REPLACE PROCEDURE to_dbg_file(p_fname varchar2, p_log varchar2) 
    -- file mode: 
    -- requires 
--- CREATE OR REPLACE DIRECTORY TMP_DIR as '/directory/where/oracle/can/write/on/DB_server/'; 
AS 
    l_file utl_file.file_type; 
BEGIN 
    l_file := utl_file.fopen('TMP_DIR', p_fname, 'A'); 
    utl_file.put_line(l_file, p_log); 
    utl_file.fflush(l_file); 
    utl_file.fclose(l_file); 
END to_dbg_file; 
/


WRITE_LOG

WRITE_LOG, które mogą przełączać się pomiędzy 2 wykorzystuje, albo dezaktywować t o unikać utraty wydajności (g_DEBUG:=FALSE).

CREATE OR REPLACE PROCEDURE write_log(p_log varchar2) AS 
    -- g_DEBUG can be set as a package variable defaulted to FALSE 
    -- then change it when debugging is required 
    g_DEBUG boolean := true; 
    -- the log file name can be set with several methods... 
    g_logfname varchar2(32767) := 'my_output.log'; 
    -- choose between 2 logging solutions: 
    -- file mode: 
    g_TYPE varchar2(7):= 'file'; 
    -- table mode: 
    --g_TYPE varchar2(7):= 'table'; 
    ----------------------------------------------------------------- 
BEGIN 
    if g_DEBUG then 
    if g_TYPE='file' then 
     to_dbg_file(g_logfname, p_log); 
    elsif g_TYPE='table' then 
     to_dbg_table(p_log); 
    end if; 
    end if; 
END write_log; 
/

A oto jak testować wyżej:

1) Uruchom ten (tryb pliku) z SQLPLUS:

BEGIN 
    write_log('this is a test'); 
    for i in 1..100 loop 
    DBMS_LOCK.sleep(1); 
    write_log('iter=' || i); 
    end loop; 
    write_log('test complete'); 
END; 
/

2) na serwerze bazy danych, otwórz shell i

 
    tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log 
+0

Mam nadzieję, że nikt nie używa tabel z nazwami kolumn, jak "u, d, l" ​​... – Obenland

+0

Nazwy @land, tabela i kolumna nie mają znaczenia, czy struktura, którą obsługujesz, jest poprawna. BTW czy kiedykolwiek pracowałeś dla banku z oldskulowymi bazami danych? To jest warte tego. –

+0

Przypuszczam, że miałeś na myśli "gorzej";) – quetzalcoatl

0

Jeśli masz dostęp do powłoki systemowej z PL/SQL envi ronment można nazwać netcat:

BEGIN RUN_SHELL('echo "'||p_msg||'" | nc '||p_host||' '||p_port||' -w 5'); END; 

p_msg - to komunikat dziennika v_host jest gospodarzem uruchomiony skrypt Pythona, który odczytuje dane z gniazda na porcie v_port.

Użyłem tego projektu, pisząc aplogr do monitorowania logów powłoki i pl/sql w czasie rzeczywistym.

+0

Proszę nie dodawać [tej samej odpowiedzi] (link) do wielu pytań. Odpowiedz na najlepszą i oznacz flagę jako duplikaty. Zobacz [Czy dopuszczalne jest dodanie duplikowanej odpowiedzi na kilka pytań?] (Http://meta.stackexchange.com/q/104227/347985) – Mogsdad

Powiązane problemy