我的长时间 SQL*Plus 循环在执行期间不打印 DBMS_OUTPUT.PUT_LINE 输出
My long time SQL*Plus loop doesn't print DBMS_OUTPUT.PUT_LINE output during execution
我知道为了在 sqlplus 上打印如下内容:
begin
dbms_output.put_line('Hello!');
end;
/
我需要打电话
set serveroutput on;
在那之前。
我也知道不需要,但我也可以调用
DBMS_OUTPUT.enable;
之前,以防万一。这对我有用。
但是如果我想一直打印一个长循环的进度怎么办?这对我来说似乎是不可能的。我已经尝试了一切以在下面的循环中打印一些进度,但就是行不通。有什么办法吗?我什至尝试假脱机到一个文件,但没有成功。
注意 1:我无法截断或分区这个 table 因为 DBA 不想帮助我,所以我不得不使用这个讨厌的循环...
注意 2:我注意到一旦循环完成,就会打印出整个输出。看起来 oracle 正在缓冲输出并在最后打印所有内容。我不确定如何避免这种情况并在每次循环迭代时打印。
set serveroutput on;
declare
e number;
i number;
nCount number;
f number;
begin
DBMS_OUTPUT.enable;
dbms_output.put_line('Hello!');
select count(*) into e from my_big_table where upd_dt < to_date(sysdate-64);
f :=trunc(e/10000)+1;
for i in 1..f
loop
delete from my_big_table where upd_dt < to_date(sysdate-64) and rownum<=10000;
commit;
DBMS_OUTPUT.PUT_LINE('Progress: ' || to_char(i) || ' out of ' || to_char(f));
end loop;
end;
感谢您的回答。
DBMS_OUTPUT 只会在 PL/SQL 代码终止并且控制返回给调用程序后才会显示。
如您所见,输出已缓冲。当您的 PL/SQL 代码完成时,调用程序(例如 SQL*Plus)可以去获取该输出。
插入另一个 table,也许称之为“MYOUTPUT”。
创建 table:
create table myoutput (lineno number, outline varchar2(80));
删除后添加:
insert into MYOUTPUT values (i,'Progress: ' || to_char(i) || ' out of ' || to_char(f));
然后 select 从 MYOUTPUT 定期查看进度。
select outline from myoutput order by lineno;
鲍比
您可以使用 UTL_FILE 将输出写入外部文件,如:
DECLARE
fh UTL_FILE.FILE_TYPE;
nRow_count NUMBER := 0;
BEGIN
fh := UTL_FILE.FOPEN('DIRECTORY_NAME', 'some_file.txt', 'w');
FOR aRow IN (SELECT *
FROM SOME_TABLE)
LOOP
nRow_count := nRow_count + 1;
IF nRow_count MOD 1000 = 0 THEN
UTL_FILE.PUT_LINE(fh, 'Processing row ' || nRow_count);
UTL_FILE.FFLUSH(fh);
END IF;
-- Do something useful with the data in aRow
END LOOP; -- aRow
UTL_FILE.FCLOSE_ALL; -- Close all open file handles, including
-- the ones I've forgotten about...
END;
此类事情有两种标准方法:
在您的会话中设置模块和操作 DBMS_APPLICATION_INFO.SET_MODULE:
SQL> exec DBMS_APPLICATION_INFO.SET_MODULE('my_long_process', '1 from 100');
PL/SQL procedure successfully completed.
SQL> select action from v$session where module='my_long_process';
ACTION
----------------------------------------------------------------
1 from 100
设置session_longops:
DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS
我建议您使用它,因为它专为长时间操作而设计。
Example on Oracle-Base.
----
PS: dbms_output,put_line 将所有输出保存在 dbms_output 包的集合(嵌套 table)变量中,所以你不能从另一个会话获取它,客户端在用户调用(执行)期间无法获取它。除了 set serveroutput on
之外,您还可以使用 dbms_output.get_lines 获取输出:http://orasql.org/2017/12/10/sqlplus-tips-8-dbms_output-without-serveroutput-on/
顺便说一句,如果您需要过滤或分析 dbms_output 的输出,有时在查询中获取输出很方便,因此您可以在 where 子句中使用过滤字符串或聚合它们:https://gist.github.com/xtender/aa12b537d3884f4ba82eb37db1c93c25
我知道为了在 sqlplus 上打印如下内容:
begin
dbms_output.put_line('Hello!');
end;
/
我需要打电话
set serveroutput on;
在那之前。 我也知道不需要,但我也可以调用
DBMS_OUTPUT.enable;
之前,以防万一。这对我有用。
但是如果我想一直打印一个长循环的进度怎么办?这对我来说似乎是不可能的。我已经尝试了一切以在下面的循环中打印一些进度,但就是行不通。有什么办法吗?我什至尝试假脱机到一个文件,但没有成功。
注意 1:我无法截断或分区这个 table 因为 DBA 不想帮助我,所以我不得不使用这个讨厌的循环...
注意 2:我注意到一旦循环完成,就会打印出整个输出。看起来 oracle 正在缓冲输出并在最后打印所有内容。我不确定如何避免这种情况并在每次循环迭代时打印。
set serveroutput on;
declare
e number;
i number;
nCount number;
f number;
begin
DBMS_OUTPUT.enable;
dbms_output.put_line('Hello!');
select count(*) into e from my_big_table where upd_dt < to_date(sysdate-64);
f :=trunc(e/10000)+1;
for i in 1..f
loop
delete from my_big_table where upd_dt < to_date(sysdate-64) and rownum<=10000;
commit;
DBMS_OUTPUT.PUT_LINE('Progress: ' || to_char(i) || ' out of ' || to_char(f));
end loop;
end;
感谢您的回答。
DBMS_OUTPUT 只会在 PL/SQL 代码终止并且控制返回给调用程序后才会显示。
如您所见,输出已缓冲。当您的 PL/SQL 代码完成时,调用程序(例如 SQL*Plus)可以去获取该输出。
插入另一个 table,也许称之为“MYOUTPUT”。
创建 table:
create table myoutput (lineno number, outline varchar2(80));
删除后添加:
insert into MYOUTPUT values (i,'Progress: ' || to_char(i) || ' out of ' || to_char(f));
然后 select 从 MYOUTPUT 定期查看进度。
select outline from myoutput order by lineno;
鲍比
您可以使用 UTL_FILE 将输出写入外部文件,如:
DECLARE
fh UTL_FILE.FILE_TYPE;
nRow_count NUMBER := 0;
BEGIN
fh := UTL_FILE.FOPEN('DIRECTORY_NAME', 'some_file.txt', 'w');
FOR aRow IN (SELECT *
FROM SOME_TABLE)
LOOP
nRow_count := nRow_count + 1;
IF nRow_count MOD 1000 = 0 THEN
UTL_FILE.PUT_LINE(fh, 'Processing row ' || nRow_count);
UTL_FILE.FFLUSH(fh);
END IF;
-- Do something useful with the data in aRow
END LOOP; -- aRow
UTL_FILE.FCLOSE_ALL; -- Close all open file handles, including
-- the ones I've forgotten about...
END;
此类事情有两种标准方法:
在您的会话中设置模块和操作 DBMS_APPLICATION_INFO.SET_MODULE:
SQL> exec DBMS_APPLICATION_INFO.SET_MODULE('my_long_process', '1 from 100'); PL/SQL procedure successfully completed. SQL> select action from v$session where module='my_long_process'; ACTION ---------------------------------------------------------------- 1 from 100
设置session_longops: DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS
我建议您使用它,因为它专为长时间操作而设计。
Example on Oracle-Base.
----
PS: dbms_output,put_line 将所有输出保存在 dbms_output 包的集合(嵌套 table)变量中,所以你不能从另一个会话获取它,客户端在用户调用(执行)期间无法获取它。除了 set serveroutput on
之外,您还可以使用 dbms_output.get_lines 获取输出:http://orasql.org/2017/12/10/sqlplus-tips-8-dbms_output-without-serveroutput-on/
顺便说一句,如果您需要过滤或分析 dbms_output 的输出,有时在查询中获取输出很方便,因此您可以在 where 子句中使用过滤字符串或聚合它们:https://gist.github.com/xtender/aa12b537d3884f4ba82eb37db1c93c25