Oracle Bulk collect 和 forall语法
概述:
在处理一个大约有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而不是FOR
1 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;