每次迴圈切換 PL/SQL → SQL 引擎,上下文切換開銷大。`FORALL` 批次綁定陣列值一次性提交,大幅降低切換次數。
FORALL i IN lower_bound .. upper_bound -- 必須連續、不可跳過
嵌套表刪除中間元素後無法直接用 FORALL。
FORALL i IN INDICES OF sparse_collection
[BETWEEN low AND high] -- 可選範圍限制
sql_statement;
自動略過未初始化索引,只處理現有元素。
-- 建立索引陣列,順序即執行順序
TYPE num_arr IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
idx_arr num_arr;
idx_arr(1) := 5; -- 先處理第 5 筆
idx_arr(2) := 2; -- 再處理第 2 筆
idx_arr(3) := 9;
FORALL i IN VALUES OF idx_arr
sql_statement;
DECLARE
TYPE dept_tab IS TABLE OF departments%ROWTYPE;
depts dept_tab;
TYPE idx_tab IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
it_idx idx_tab;
v_cnt PLS_INTEGER := 0;
BEGIN
-- 1. 批次讀入所有部門
SELECT * BULK COLLECT INTO depts FROM departments;
-- 2. 篩選 IT 部門,記錄索引
FOR i IN 1..depts.COUNT LOOP
IF depts(i).department_name LIKE 'IT%' THEN
v_cnt := v_cnt + 1;
it_idx(v_cnt) := i;
END IF;
END LOOP;
-- 3. FORALL + VALUES OF 批次 INSERT 到暫存表
FORALL j IN VALUES OF it_idx
INSERT INTO temp_it_depts VALUES depts(it_idx(j));
DBMS_OUTPUT.PUT_LINE('Inserted ' || SQL%ROWCOUNT || ' IT departments');
END;
/
-- 輸出
Inserted 3 IT departments
| 方式 | 1000 筆耗時(秒) | 備註 |
|---|---|---|
| FOR LOOP + INSERT | ~2.8 | 1000 次上下文切換 |
| FORALL 連續 | ~0.15 | 單次切換 |
| FORALL + VALUES OF | ~0.16 | 含索引陣列建構開銷 |