47

我需要在 pl/sql 中调试以计算程序的时间,我想使用:

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

但我不明白输出的位置以及如何将其重定向到包含我要收集的所有数据的日志文件?

4

10 回答 10

38

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
于 2009-09-21T10:05:18.063 回答
33

作为写入文件的替代方法,写入表怎么样?您可以调用自己的 DEBUG.OUTPUT 过程,而不是调用 DBMS_OUTPUT.PUT_LINE,例如:

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。

当然,您需要管理该表,使其不会永远增长!一种方法是每晚/每周运行并删除任何“旧”的调试消息。

于 2009-09-21T10:34:46.007 回答
16

如果您只是在 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 可以通过其他方式捕获输出,但我不熟悉如何。

于 2009-09-21T09:24:56.057 回答
14

使用 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;
于 2013-04-16T05:46:27.363 回答
5

除了 Tony 的回答之外,如果您想了解您的 PL/SQL 程序将时间花在哪里,还值得查看Oracle PL/SQL 文档的这一部分。

于 2009-09-21T10:41:35.853 回答
3

使用UTL_FILE而不是DBMS_OUTPUT将输出重定向到文件:

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

于 2009-09-21T09:11:50.497 回答
3

作为旁注,请记住所有这些输出都是在服务器端生成的。

使用 DBMS_OUTPUT,文本在服务器执行查询时生成并存储在缓冲区中。当服务器完成查询数据检索时,它会被重定向到您的客户端应用程序。也就是说,您只能在查询结束时获得此信息。

使用 UTL_FILE 记录的所有信息都将存储在服务器的文件中。执行完成后,您必须导航到此文件以获取信息。

希望这可以帮助。

于 2009-09-21T09:50:04.693 回答
1

它可以将文件直接写入托管数据库的数据库服务器,并且随着 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)在数据库服务器上,打开一个shell和

    tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log
于 2016-09-23T14:09:55.477 回答
-1

一个旧线程,但还有另一种选择。

从 9i 开始,您可以使用流水线表功能。

首先,创建一个类型作为 varchar 表:

CREATE TYPE t_string_max IS TABLE OF VARCHAR2(32767);

其次,将代码包装在流水线函数声明中:

CREATE FUNCTION fn_foo (bar VARCHAR2) -- your params
  RETURN t_string_max PIPELINED IS 
  -- your vars
BEGIN
  -- your code
END;
/

全部替换DBMS_OUTPUT.PUT_LINEPIPE ROW.

最后,这样称呼它:

SELECT * FROM TABLE(fn_foo('param'));

希望能帮助到你。

于 2016-07-20T14:29:01.430 回答
-4

尝试这个:

SELECT systimestamp INTO time_db FROM dual ;

DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
于 2013-05-16T13:32:54.247 回答