2009-09-24 25 views
33

Tengo un script SQL que se llama desde un script de shell y tarda mucho tiempo en ejecutarse. Actualmente contiene dbms_output.put_line declaraciones en varios puntos. El resultado de estas instrucciones de impresión aparece en los archivos de registro, pero solo una vez que se ha completado.¿Hay alguna manera de descargar la salida de PL/SQL en Oracle?

¿Hay alguna forma de garantizar que la salida aparezca en el archivo de registro mientras se ejecuta la secuencia de comandos?

Respuesta

46

No realmente. La forma en que DBMS_OUTPUT funciona es la siguiente: tu bloque PL/SQL se ejecuta en el servidor de la base de datos sin interacción con el cliente. Entonces, cuando llamas a PUT_LINE, solo estás poniendo ese texto en un búfer en la memoria del servidor. Cuando se completa el bloque PL/SQL, se devuelve el control al cliente (supongo que SQLPlus en este caso); en ese punto, el cliente saca el texto del búfer llamando a GET_LINE y lo muestra.

De modo que la única forma en que puede hacer que la salida aparezca más frecuentemente en el archivo de registro es dividir un bloque PL/SQL grande en varios bloques más pequeños, para que el control se devuelva al cliente más a menudo. Esto puede no ser práctico dependiendo de lo que esté haciendo su código.

Otras alternativas son usar UTL_FILE para escribir en un archivo de texto, que se puede eliminar cuando lo desee, o usar un procedimiento de transacción autónoma para insertar instrucciones de depuración en una tabla de base de datos y confirmar después de cada una.

4

se lee la memoria intermedia de DBMS_OUTPUT cuando se llama al procedimiento DBMS_OUTPUT.get_line. Si su aplicación cliente es SQL * Plus, significa que solo se enjuagará una vez que el procedimiento finalice.

Puede aplicar el método descrito en this SO para escribir el buffer DBMS_OUTPUT en un archivo.

6

dos alternativas:

  1. puede insertar sus datos de registro en una tabla de registro utilizando una transacción autónoma. Puede consultar esta tabla de registro en otra sesión de SQLPLUS/Toad/sql developer etc .... Debe utilizar una transacción autónoma para que sea posible confirmar su registro sin interferir en el manejo de la transacción en su script sql principal.

  2. Otra alternativa es utilizar una función segmentada que devuelve la información de registro. Vea aquí para un ejemplo: http://berxblog.blogspot.com/2009/01/pipelined-function-vs-dbmsoutput.html Cuando usa una función pipeline no necesita usar otra sesión SQLPLUS/Toad/sql developer etc ...

3

Si es posible, debe reemplazar las llamadas a dbms_output.put_line por su propia función.

Este es el código para esta función WRITE_LOG - si usted quiere tener la posibilidad de elegir entre 2 soluciones de registro:

registros de escritura en una mesa en un 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; 
/

o escriba directamente en el servidor de bases de datos que aloja su base de datos

Este utiliza el 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

entonces el procedimiento WRITE_LOG que puede cambiar entre los 2 usos, o sea t desactivado o evitar la pérdida de rendimiento (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; 
/

Y aquí es cómo probar lo anterior:

1) Lanzamiento de este (modo de archivo) de su 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) en el servidor de base de datos, abrir una shell y

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

Esperemos que nadie use tablas con nombres de columna como 'u, d, l' ... – Obenland

+0

@Oberland, los nombres de tablas y columnas no importan si el marco que maneja a sus usuarios es correcto. Por cierto, ¿alguna vez has trabajado para un banco con bases de datos de la vieja escuela? Vale más que eso. –

+0

Supongo que quiere decir "peor";) – quetzalcoatl

0

Si tiene acceso al shell del sistema desde PL/SQL envi ronment puede llamar netcat:

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

p_msg - es un mensaje de registro v_host es un script en Python host que ejecute que lee datos de socket en el puerto v_port.

Utilicé este diseño cuando escribí aplogr para la supervisión de registros de shell y pl/sql en tiempo real.

+0

No agregue [la misma respuesta] (enlace) a varias preguntas. Responda el mejor y marque el resto como duplicados. Ver [¿Es aceptable agregar una respuesta duplicada a varias preguntas?] (Http://meta.stackexchange.com/q/104227/347985) – Mogsdad

Cuestiones relacionadas