我需要在大约300000行的游标中进行一些插入,然而这运行得很慢,有关如何让它运行得更快的任何想法?我可以通过批量提交加快速度吗?所以例如我会在第1000行之后执行提交
DECLARE
CURSOR test_cursor IS
SELECT a from database.mytable
BEGIN
FOR curRow IN test_cursor LOOP
insert into tableb (testval)
values ('something');
commit;
END LOOP;
END;
答案 0 :(得分:8)
300000行不是那么多行。除非每行极大,否则不应在批处理中间提交。
中级提交will only achieve:
如果你的进程实际上是一个在循环中有一个插入的游标,你应该运行一个语句:
BEGIN
INSERT INTO tableb (col1..coln) (SELECT col1..coln FROM database.mytable);
END;
如果您仍然需要额外的性能,可以考虑直接插入和并行操作,但可能是“仅”300k行的过度优化。
到目前为止,您可以使用的最大优化是根据集而不是传统的程序方法进行思考,而不是由批量单行语句组成。
答案 1 :(得分:3)
或者你可以试试这个:
DECLARE
CURSOR test_cursor IS
SELECT col1 from table_a;
TYPE fetch_array IS TABLE OF test_cursor%ROWTYPE;
test_array fetch_array;
l_errors PLS_INTEGER;
l_dml_errors EXCEPTION;
PRAGMA EXCEPTION_INIT(l_dml_errors, -24381);
BEGIN
open test_cursor;
loop
fetch test_cursor bulk collect into test_array limit 10000;
forall i in 1..test_array.count save exceptions
insert into table_b(col1)
values(test_array(i).col1);
exit when test_cursor%notfound;
end loop;
close test_cursor;
commit;
EXCEPTION
WHEN l_dml_errors THEN
l_errors := SQL%BULK_EXCEPTIONS.COUNT;
dbms_output.put_line('Number of INSERT statements that failed: ' || l_errors);
FOR i IN 1 .. l_errors
LOOP
dbms_output.put_line('Error #' || i || ' at '|| 'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
dbms_output.put_line('Error message is ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
END;
答案 2 :(得分:0)
我不建议使用游标方法。我使用追加并行提示这样的情况。大多数情况下,您的查询字面上运行的速度是N次,其中N是并行度。使用nologging / noarchivelog绕过灾难恢复有时是一个好主意。
对于真正大型的迁移(几十到几百GB),我发现在表的自然键(通常是日期)上批处理是个好主意。周围的一些少量状态可以让你在必要时随意取消+恢复迁移。
答案 3 :(得分:-1)
可能会这会帮助你试试这个
DECLARE
i number;
CURSOR test_cursor IS
SELECT a from database.mytable
BEGIN
FOR curRow IN test_cursor LOOP
insert into tableb (testval)
values ('something');
i:i+1;
if mod(i,1000)=0 then
commit;
end if;
END LOOP;
commit;
END;