forall分批提交oracle,bulk collect into forall insert批量分次提交

难免开始以为批量提交的小事务会比一个大事务完成后一次提示会更快,可以TOM也再三强调这种想法是不对的,如果非要分次,最好的方法是按业务过程的要求以适当的频度提交,并且相应地设置undo大小 。

今天刚好网友问到我这个问题,下面看我的例子

SQL> create table obj as select * from all_objects;

Table created.

Elapsed: 00:00:04.15

SQL> select count(*) from obj;

COUNT(*)

----------

40696

Elapsed: 00:00:00.05

方法1

SQL> l

1 declare

2 v_cmt_cnt number:=0;

3 cursor c is select * from obj;

4 type v_rows is table of c%rowtype;

5 v_t v_rows;

6 begin

7 open c;

8 loop

9 v_cmt_cnt:=v_cmt_cnt+1;

10 fetch c bulk collect into v_t limit 1000;

11 forall i in 1..v_t.count

12 insert into obj values v_t(i);

13 commit;

14 exit when c%notfound;

15 end loop;

16 close c;

17 dbms_output.put_line('commited times:'||v_cmt_cnt);

18* end;

commited times:41

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.49

SQL> select count(*) from obj;

COUNT(*)

----------

81392

Elapsed: 00:00:00.02

SQL> select 40696*2 from dual;

40696*2

----------

81392

Elapsed: 00:00:00.01

SQL> rollback;

Rollback complete.

Elapsed: 00:00:00.01

SQL> select count(*) from obj;

COUNT(*)

----------

81392

--也可以加append ,archive模式下 table nologging

declare

v_cmt_cnt number:=0;

cursor c is select * from obj;

type v_rows is table of c%rowtype;

v_t v_rows;

begin

open c;

loop

v_cmt_cnt:=v_cmt_cnt+1;

fetch c bulk collect into v_t limit 1000;

forall i in 1..v_t.count

insert /*+ append */ into obj values v_t(i);

commit;

exit when c%notfound;

end loop;

close c;

dbms_output.put_line('commited times:'||v_cmt_cnt);

end;

Elapsed: 00:00:00.53

--比较了一下执行速度是logging 无append hint 要快几毫秒,append nologging是REDO 的生成少了些

--redo检查方法select a.name,b.value from v$statname a,v$sesstat b where a.statistic#=b.statistic# and a.name = 'redo size' and sid=:sid(v$mystat);

SQL> select 13991040-9331292 nolog_append,9331292-4659380 log_noappend from dual;

NOLOG_APPE LOG_NOAPPE

---------- ----------

4659748 4671912

方法2,

SQL> l

1 declare

2 v_cmt_cnt number:=0;

3 begin

4 for c in(select rowid rid,rownum r from obj)

5 loop

6 insert into obj select * from obj where rowid=c.rid;

7 if(mod(c.r,1000)=0)then

8 commit;

9 v_cmt_cnt:=v_cmt_cnt+1;

10 end if;

11 end loop;

12 commit;

13 dbms_output.put_line('commited times:'||v_cmt_cnt);

14* end;

commited times:40

PL/SQL procedure successfully completed.

Elapsed: 00:00:14.98

redo前后值

SQL> select 40867092-27459428

2 from dual;

40867092-27459428

-----------------

13407664

可以看到这种方法比方法1慢了14秒,redo也大约增加了300%

SQL> insert /*+append*/ into obj select * from obj;

40696 rows created.

Elapsed: 00:00:00.30

SQL> commit;

Commit complete.

Elapsed: 00:00:00.02

redo:4709556

--各测试都是drop table 后重建的

SQL> insert into obj select * from obj;

40696 rows created.

Elapsed: 00:00:00.36

SQL> commit;

Commit complete.

Elapsed: 00:00:00.02

redo:4643984

--为了避免查询REDO附加REDO,以上的测试REDO也都是在另一SESSION中查询

note:测试就做到这,一般来说一个事务是最快的,不要认为多个小事务就比大事务快,bulk collect into forall批量的方式会比单条loop更快些,分次提交有可能面临如果执行一半失败的问题。

— batch update —

DECLARE

v_cmt_cnt number:=0;

Type tRowid Is Table Of rowid Index By Binary_Integer;

type tname Is Table Of userinfo.name%TYPE;

vRowId tRowId;

vname tname;

CURSOR c is

SELECT rowid ,name FROM userinfo where 1=1;

BEGIN

OPEN c;

LOOP

FETCH c BULK COLLECT INTO vROWID,vname limit 1000;

v_cmt_cnt:=v_cmt_cnt+1;

forall i in 1..vROWID.count

update userinfo set cdate=sysdate,name=vname(i)||'t' WHERE rowid=vRowId(i);

commit;

EXIT when c%NOTFOUND;

END LOOP;

CLOSE c;

dbms_output.put_line('Commits:'||v_cmt_cnt);

EXCEPTION

WHEN OTHERS THEN

NULL;

END;

打赏

8732971891f4ba05583674ca6b8145ac.png微信扫一扫,打赏作者吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值