web-dev-qa-db-ja.com

DBMS_OUTPUT.PUT_LINEの出力をファイルにリダイレクトする方法

プロシージャの時間を計算するには、pl/sqlでデバッグする必要があります。

SELECT systimestamp FROM dual INTO time_db;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);

しかし、出力がどこに行くのか理解できず、収集したいすべてのデータを含むログファイルに出力をリダイレクトするにはどうすればよいですか?

45
aye

DBMS_OUTPUTは、ほとんどの環境でネイティブに使用されないため、デバッグに最適なツールではありません。ただし、DBMS_OUTPUTの出力をキャプチャする場合は、DBMS_OUTPUT.get_lineプロシージャを使用するだけです。

以下に小さな例を示します。

SQL> create directory tmp as '/tmp/';

Directory created

SQL> CREATE OR REPLACE PROCEDURE write_log AS
  2     l_line VARCHAR2(255);
  3     l_done NUMBER;
  4     l_file utl_file.file_type;
  5  BEGIN
  6     l_file := utl_file.fopen('TMP', 'foo.log', 'A');
  7     LOOP
  8        EXIT WHEN l_done = 1;
  9        dbms_output.get_line(l_line, l_done);
 10        utl_file.put_line(l_file, l_line);
 11     END LOOP;
 12     utl_file.fflush(l_file);
 13     utl_file.fclose(l_file);
 14  END write_log;
 15  /

Procedure created

SQL> BEGIN
  2     dbms_output.enable(100000);
  3     -- write something to DBMS_OUTPUT
  4     dbms_output.put_line('this is a test');
  5     -- write the content of the buffer to a file
  6     write_log;
  7  END;
  8  /

PL/SQL procedure successfully completed

SQL> Host cat /tmp/foo.log

this is a test
37
Vincent Malgrat

ファイルに書き込む代わりに、テーブルに書き込むのはどうですか? DBMS_OUTPUT.PUT_LINEを呼び出す代わりに、次のような独自のDEBUG.OUTPUTプロシージャを呼び出すことができます。

procedure output (p_text varchar2) is
   pragma autonomous_transaction;
begin
   if g_debugging then
      insert into debug_messages (username, datetime, text)
      values (user, sysdate, p_text);
      commit;
   end if;
end;

自律型トランザクションを使用すると、ファイルを使用している場合に発生するように、ロールバックされたトランザクションから生成されたデバッグメッセージを保持できます(たとえば、例外が発生した後)。

G_debuggingブール変数は、デフォルトでfalseに設定され、デバッグ出力が必要な場合にtrueに設定できるパッケージ変数です。

もちろん、永久に成長しないように、そのテーブルを管理する必要があります! 1つの方法は、夜間/毎週実行し、「古い」デバッグメッセージを削除するジョブです。

31
Tony Andrews

SQL PlusでPL/SQLをテストするだけの場合は、次のようなファイルに転送できます。

spool output.txt
set serveroutput on

begin
  SELECT systimestamp FROM dual INTO time_db;
  DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
end;
/

spool off

ToadやSQL DeveloperなどのIDEは他の方法で出力をキャプチャできますが、その方法についてはよく知りません。

14
Tony Andrews

set serveroutput onを使用します。

例えば:

set serveroutput on;

DECLARE
x NUMBER;
BEGIN
x := 72600;
dbms_output.put_line('The variable X = '); dbms_output.put_line(x);
END;
14
Mahmoud Hanafy

Tonyの答えに加えて、PL/SQLプログラムがどこで時間を費やしているのかを調べたい場合は、Oracle PL/SQLのドキュメントの一部である this をチェックする価値があります。

5
Ian Carpenter

補足として、この出力はすべてサーバー側で生成されることに注意してください。

DBMS_OUTPUTを使用すると、クエリの実行中にサーバーでテキストが生成され、バッファーに保存されます。サーバーがクエリデータの取得を完了すると、クライアントアプリにリダイレクトされます。つまり、クエリが終了したときにのみこの情報を取得します。

UTL_FILEを使用すると、記録されたすべての情報がサーバーのファイルに保存されます。実行が終了したら、このファイルに移動して情報を取得する必要があります。

お役に立てれば。

3
Juan Calero

UTL_FILEの代わりにDBMS_OUTPUTを使用すると、出力がファイルにリダイレクトされます。

http://oreilly.com/catalog/oraclebip/chapter/ch06.html

3
Rafa de Castro

データベースをホストするDBサーバーにファイルを直接書き込むことができ、PL/SQLプログラムの実行に伴ってすべてが変更されます。

これは、OracleディレクトリTMP_DIR;宣言し、以下の手順を作成する必要があります。

CREATE OR REPLACE PROCEDURE write_log(p_log varchar2)
  -- file mode; thisrequires
--- 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', 'my_output.log', 'A');
  utl_file.put_line(l_file, p_log);
  utl_file.fflush(l_file);
  utl_file.fclose(l_file);
END write_log;
/

使用方法は次のとおりです。

1)SQL * PLUSクライアントからこれを起動します。

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)データベースサーバーで、シェルを開き、

 tail -f -n500 /directory/where/Oracle/can/write/on/DB_server/my_output.log
1
J. Chomel