概述:
在处理一个大约有400W数据的表中的冗余数据,使用cursor来一条一条处理的时候,发现耗时大约为5 hours左右。之后采用Oracle提供的BULK COLLECT和FORALL改写程序,耗时降到1个小时左右,速度提高了5倍左右。原因是:
- 使用BLUK COLLECT一次取出一个数据集合,比用游标条取数据效率高,尤其是在网络不大好的情况下。但BLUK COLLECT需要大量内存。
- 使用FORALL比FOR效率高,因为前者只切换一次上下文,而后者将是在循环次数一样多个上下文间切换。
1. select into中使用bulk collect
SELECT id, code BULK COLLECT INTO v_table;
2. fetch into中使用bulk collect
fetch cursor1 BULK COLLECT INTO v_table;
3. returning into中使用bulk collect
DELETE FROM table1 WHERE id = 1 RETURNING id, code BULK COLLECT INTO v_table;4. 批量更新中,使用forall而不是FOR1 DECLARE 2 TYPE NumList IS VARRAY(20) OF NUMBER; 3 depts NumList := NumList(10, 30, 70); 4 BEGIN 5 FOR i IN depts.FIRST .. depts.LAST LOOP 6 UPDATE t_test SET sal = sal * 1.10 WHERE deptno = depts(i); 7 END LOOP; 8 END;
改用FORALL后:
1 DECLARE 2 TYPE NumList IS VARRAY(20) OF NUMBER; 3 depts NumList := NumList(10, 30, 70); 4 BEGIN 5 FORALL i IN depts.FIRST..depts.LAST 6 UPDATE emp SET sal = sal * 1.10 WHERE deptno = depts(i); 7 END;
1 declare 2 TYPE REL IS RECORD( 3 id T_REL.id%TYPE, 4 code T_REL.code%TYPE, 5 ); 6 7 TYPE TABLE_REL IS TABLE OF REL INDEX BY BINARY_INTEGER; 8 var_rel TABLE_REL; 9 10 cursor cur_MAX_REL is 11 SELECT max(id) as id 12 FROM T_REL 13 GROUP BY code; 14 15 begin 16 open cur_MAX_REL; 17 loop 18 FETCH cur_MAX_REL BULK COLLECT 19 INTO var_rel LIMIT 10000; 20 21 FORALL i IN var_rel.FIRST .. var_rel.LAST 22 insert into t_test 23 (id, code) 24 values var_rel(i); 25 26 exit when cur_MAX_REL%NOTFOUND; 27 end loop; 28 close cur_MAX_REL; 29 commit; 30 EXCEPTION 31 WHEN OTHERS THEN 32 IF cur_MAX_REL%ISOPEN THEN 33 CLOSE cur_MAX_REL; 34 END IF; 35 dbms_output.put_line(chr(10) || sqlerrm); 36 END;