我需要在pl / sql中调试以计算程序的时间,我想使用:
SELECT systimestamp FROM dual INTO time_db;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
但我不明白输出的位置以及如何将其重定向到包含我想要收集的所有数据的日志文件?
答案 0 :(得分:36)
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
答案 1 :(得分:30)
作为写入文件的替代方法,如何写入表格?您可以调用自己的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。
当然,您需要管理该表,以使其不会永远增长!一种方法是每晚/每周运行的作业,并删除任何“旧”的调试消息。
答案 2 :(得分:13)
如果您只是在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可以通过其他方式捕获输出,但我不熟悉如何。
答案 3 :(得分:13)
使用 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;
答案 4 :(得分:5)
除了Tony的回答之外,如果您想了解PL / SQL程序花费的时间,还需要查看Oracle {/ 3}}部分Oracle PL / SQL文档。
答案 5 :(得分:3)
使用UTL_FILE
代替DBMS_OUTPUT
会将输出重定向到文件:
答案 6 :(得分:3)
作为旁注,请记住所有这些输出都是在服务器端生成的。
使用DBMS_OUTPUT,文本在服务器执行查询时生成并存储在缓冲区中。然后,当服务器完成查询数据检索时,它会重定向到您的客户端应用程序。也就是说,只有在查询结束时才会收到此信息。
使用UTL_FILE记录的所有信息都将存储在服务器的文件中。执行完成后,您必须导航到此文件才能获取信息。
希望这有帮助。
答案 7 :(得分:1)
它可以直接将文件写入托管数据库的数据库服务器,并且随着PL / SQL程序的执行而改变。
这使用 Oracle directory 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
答案 8 :(得分:-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_LINE
的所有PIPE ROW
。
最后,请这样称呼:
SELECT * FROM TABLE(fn_foo('param'));
希望它有所帮助。
答案 9 :(得分:-4)
试试这个:
SELECT systimestamp INTO time_db FROM dual ;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);