1. 程式人生 > >PL/SQL批處理語句(一)BULK COLLECT

PL/SQL批處理語句(一)BULK COLLECT

數據 使用 for循環 差異 code 基於 name 從表 允許

我們知道PL/SQL程序中運行SQL語句是存在開銷的,因為SQL語句是要提交給SQL引擎處理,這種在PL/SQL引擎和SQL引擎之間的控制轉移叫做上下文卻換,每次卻換時,都有額外的開銷。
然而,FORALL和BULK COLLECT可以讓PL/SQL引擎把多個上下文卻換壓縮成一個,這使得在PL/SQL中的要處理多行記錄的SQL語句執行的花費時間驟降。
技術分享圖片

技術分享圖片

示例:
一、BULK COLLECT將所得的結果集一次性綁定(全部)

--下面的示例中使用了BULK COLLECT將得到的結果集綁定到記錄變量中        
DECLARE
   TYPE emp_rec_type IS RECORD  
--聲明記錄類型 ( empno emp.empno%TYPE ,ename emp.ename%TYPE ,hiredate emp.hiredate%TYPE ); TYPE nested_emp_type IS TABLE OF emp_rec_type; --聲明記錄類型變量 emp_tab nested_emp_type;
BEGIN SELECT empno, ename, hiredate BULK COLLECT INTO emp_tab
--使用BULK COLLECT 將所得的結果集一次性綁定到記錄變量emp_tab中
FROM emp; FOR i IN emp_tab.FIRST .. emp_tab.LAST LOOP DBMS_OUTPUT.put_line(
Current record is ||emp_tab(i).empno||chr(9)||emp_tab(i).ename||chr(9)||emp_tab(i).hiredate); END LOOP;
END;
--上面的例子可以通過FOR 循環和普通的SELECT INTO來實現,那兩者之間的差異呢? --差異是FOR循環的SELECT INTO逐行提取並綁定到記錄變量,而BULK COLLECT則一次即可提取所有行並綁定到記錄變量。即謂批量綁定。




二、使用LIMIT限制FETCH數據量(限制數量)
在使用BULK COLLECT 子句時,對於集合類型,如嵌套表,聯合數組等會自動對其進行初始化以及擴展(如下示例)。因此如果使用BULK COLLECT子句操作集合,則無需對集合進行初始化以及擴展。由於BULK COLLECT的批量特性,如果數據量較大,而集合在此時又自動擴展,為避免過大的數據集造成性能下降,因此使用limit子句來限制一次提取的數據量。limit子句只允許出現在fetch操作語句的批量中。
用法:
FETCH ... BULK COLLECT INTO ... [LIMIT rows]

DECLARE
   CURSOR emp_cur IS
      SELECT empno, ename, hiredate FROM emp;

   TYPE emp_rec_type IS RECORD
   (
      empno      emp.empno%TYPE
     ,ename      emp.ename%TYPE
     ,hiredate   emp.hiredate%TYPE
   );

   TYPE nested_emp_type IS TABLE OF emp_rec_type;   -->定義了基於記錄的嵌套表
   emp_tab     nested_emp_type;           -->定義集合變量,此時未初始化
v_limit PLS_INTEGER :
= 5; -->定義了一個變量來作為limit的值 v_counter PLS_INTEGER := 0; BEGIN OPEN emp_cur; LOOP FETCH emp_cur BULK COLLECT INTO emp_tab -->fetch時使用了BULK COLLECT子句 LIMIT v_limit; -->使用limit子句限制提取數據量 EXIT WHEN emp_tab.COUNT = 0; -->註意此時遊標退出使用了emp_tab.COUNT,而不是emp_cur%notfound v_counter := v_counter + 1; -->記錄使用LIMIT之後fetch的次數 FOR i IN emp_tab.FIRST .. emp_tab.LAST LOOP DBMS_OUTPUT.put_line( Current record is ||emp_tab(i).empno||CHR(9)||emp_tab(i).ename||CHR(9)||emp_tab(i).hiredate); END LOOP; END LOOP; CLOSE emp_cur; DBMS_OUTPUT.put_line( The v_counter is || v_counter ); END;


三、使用 RETURNING 子句的批量綁定
BULK COLLECT除了與SELECT,FETCH進行批量綁定之外,還可以與INSERT,DELETE,UPDATE語句結合使用。當與這幾個DML語句結合時,我們
需要使用RETURNING子句來實現批量綁定。

--下面示例中從表emp中刪除所有deptno=20的記錄
DECLARE
   TYPE emp_rec_type IS RECORD
   (
      empno      emp.empno%TYPE
     ,ename      emp.ename%TYPE
     ,hiredate   emp.hiredate%TYPE
   );

   TYPE nested_emp_type IS TABLE OF emp_rec_type;
   emp_tab   nested_emp_type;
-- v_limit PLS_INTEGER := 3; -- v_counter PLS_INTEGER := 0; BEGIN DELETE FROM emp WHERE deptno = 20 RETURNING empno, ename, hiredate -->使用returning 返回這幾個列 BULK COLLECT INTO emp_tab; -->將前面返回的列的數據批量插入到集合變量 DBMS_OUTPUT.put_line( Deleted || SQL%ROWCOUNT || rows. ); COMMIT; IF emp_tab.COUNT > 0 THEN -->當集合變量不為空時,輸出所有被刪除的元素 FOR i IN emp_tab.FIRST .. emp_tab.LAST LOOP DBMS_OUTPUT. put_line( Current record || emp_tab( i ).empno || CHR( 9 ) || emp_tab( i ).ename || CHR( 9 ) || emp_tab( i ).hiredate || has been deleted ); END LOOP; END IF; END;



四、BULK COLLECT的限制
1、不能對使用字符串類型作鍵的關聯數組使用BULK COLLECT 子句。
2、只能在服務器端的程序中使用BULK COLLECT,如果在客戶端使用,就會產生一個不支持這個特性的錯誤。
3、BULK COLLECT INTO 的目標對象必須是集合類型。
4、復合目標(如對象類型)不能在RETURNING INTO 子句中使用。
5、如果有多個隱式的數據類型轉換的情況存在,多重復合目標就不能在BULK COLLECT INTO 子句中使用。
6、如果有一個隱式的數據類型轉換,復合目標的集合(如對象類型集合)就不能用於BULK COLLECTINTO 子句中。

PL/SQL批處理語句(一)BULK COLLECT