x.5*_*509 3 oracle logging plsql dbms-output
我有以下过程填充列中的空值.如果我有非常小的数据集,该过程工作正常.但我所针对的数据大约有30亿条记录.只需在100万条记录中测试这个脚本就会抛出这些行为.
ORA-20000: ORU-10027: buffer overflow, limit of 20000 bytes
ORA-06512: at "SYS.DBMS_OUTPUT", line 32
ORA-06512: at "SYS.DBMS_OUTPUT", line 97
ORA-06512: at "SYS.DBMS_OUTPUT", line 112
ORA-06512: at "DBNAME.PRBACKFILLI", line 39
ORA-06512: at line 2
Run Code Online (Sandbox Code Playgroud)
经过一点挖掘后,我意识到DBMS_OUTPUT.PUT_LINE在程序结束时打印输出.现在问题是我们想要调试信息,我们该怎么办?
CREATE OR REPLACE PROCEDURE PRBACKFILL (str_dest IN VARCHAR2) AS
CURSOR cr_pst_ IS
select id, seq from TABLE_ where ID is null;
TYPE t_id_array IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
TYPE t_seq_array IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
a_id t_id_array;
a_seq t_seq_array;
i_bulk_limit NUMBER := 1000;
BEGIN
OPEN cr_pst_;
LOOP
FETCH cr_pst_
BULK COLLECT INTO a_id, a_seq LIMIT i_bulk_limit;
FOR i IN 1..a_id.count LOOP
a_id(i) := Floor(a_seq(i)/10000000000000);
END LOOP;
FORALL i IN 1 .. a_id.count
UPDATE TABLE_
SET ID = a_id(i)
WHERE SEQ = a_seq(i);
COMMIT;
DBMS_OUTPUT.PUT_LINE ('COMMITED '||i_bulk_limit||' records');
EXIT WHEN cr_pst_%NOTFOUND;
END LOOP; -- main cursor loop
CLOSE cr_pst_;
DBMS_OUTPUT.PUT_LINE ('Backfill completed gracefully!');
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No more records to process');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('errno: '||TO_CHAR(SQLCODE)||' Msg: ' || SQLERRM);
END PRBACKFILL;
.
/
sho err;
Run Code Online (Sandbox Code Playgroud)
Jus*_*ave 11
首先,您通常不会DBMS_OUTPUT用于记录.将数据写入日志表通常更有意义,特别是如果您的日志记录过程被定义为自治事务,以便您可以在过程运行时监视日志数据. DBMS_OUTPUT只有在整个程序执行完毕后才会显示,这一点通常都是毫无意义的.
与第一点相关,依赖于DBMS_OUTPUT向调用者表明存在某种异常是一种非常糟糕的做法.至少,您需要重新引发抛出的异常,以便获得错误堆栈以调试问题.
其次,启用输出时,必须指定DBMS_OUTPUT可写入的缓冲区的大小.您似乎已将缓冲区声明为20,000字节,如果您这样做,则默认为默认值
SQL> set serveroutput on;
Run Code Online (Sandbox Code Playgroud)
您可以通过指定大小来更改它,但最大大小限制为1,000,000字节
SQL> set serveroutput on size 1000000;
Run Code Online (Sandbox Code Playgroud)
如果你打算在1000行的行中更新30亿行,那么缓冲区就会太小了.使用当前代码,您将生成超过60倍的数据量.如果在客户端和服务器上都使用10.2,则应该能够分配无限缓冲区
SQL> set serveroutput on size unlimited;
Run Code Online (Sandbox Code Playgroud)
但这不是早期版本中的一个选项.
最后,您确定首先需要使用PL/SQL吗?通过简单地执行单个UPDATE,您似乎可以更有效地完成此操作
UPDATE table_
SET id = floor( seq/ 10000000000000 )
WHERE id is null;
Run Code Online (Sandbox Code Playgroud)
这比代码少得多,读起来容易得多,并且比PL/SQL替代方案更有效.唯一的缺点是它要求您的UNDO表空间足够大以容纳生成的UNDO,但是将单个列从NULL更新为非NULL数值不应该生成那么多UNDO.
| 归档时间: |
|
| 查看次数: |
27008 次 |
| 最近记录: |