语句本身不是forall
循环。
它的作用是将数组的所有元素一次性发送到 SQL 引擎,这使 SQL 能够插入行,而无需返回 PL/SQL 引擎来获取更多数据。
换句话说FORALL
,删除了常规 FOR 循环中的上下文切换。
我们可以用一个简单的跟踪来证明这一点。考虑:
SQL> alter session set sql_trace=true;
Session altered.
SQL> declare
2 TYPE ebRBKTable IS TABLE OF EBTDCCRBK%ROWTYPE INDEX BY PLS_INTEGER;
3 rbkTable ebRBKTable;
4 begin
5
6 for idx in 1..100000
7 loop
8 rbkTable(idx).BDADDUSERID := dbms_random.string('a', 10);
9 end loop;
10
11 forall idx in 1..rbkTable.count
12 insert into EBTDCCRBK values rbkTable(idx);
13 commit;
14
15 end;
16 /
在我们看到的 SQL 跟踪中:
INSERT INTO EBTDCCRBK
VALUES
(:B1 )
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.07 0.07 1 724 3066 100000
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.07 0.07 1 724 3066 100000
与正则循环:
SQL> alter session set sql_trace=true;
Session altered.
SQL> declare
2 TYPE ebRBKTable IS TABLE OF EBTDCCRBK%ROWTYPE INDEX BY PLS_INTEGER;
3 rbkTable ebRBKTable;
4 begin
5
6 for idx in 1..100000
7 loop
8 rbkTable(idx).BDADDUSERID := dbms_random.string('a', 10);
9 end loop;
10
11 for idx in 1..rbkTable.count
12 loop
13 insert into EBTDCCRBK values rbkTable(idx);
14 end loop;
15 commit;
16
17 end;
18 /
PL/SQL procedure successfully completed.
SQL> alter session set sql_trace=false;
跟踪文件显示:
INSERT INTO EBTDCCRBK
VALUES
(:B1 )
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100000 3.33 3.24 1 689 104216 100000
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 100001 3.33 3.24 1 689 104216 100000
请注意,该FORALL
版本中的跟踪文件只执行了一次,即 SQL 引擎一键完成了工作。在FOR LOOP
变体中,SQL 引擎有 100k 次执行,并使用更多 CPU 来完成相同的工作(因为它必须执行大量单个操作,并且会话是从 pl/sql->sql 为每个插入的行进行上下文切换.