批量SQL之 BULK COLLECT 子句

  BULK COLLECT 子句會批量檢索結果,即一次性將結果集綁定到一個集合變量中,並從SQL引擎發送到PL/SQL引擎。一般能夠在SELECT INTO、
FETCH INTO以及RETURNING INTO子句中使用BULK COLLECT。本文將逐一描述BULK COLLECT在這幾種情形下的用法。
    有關FORALL語句的用法請參考:批量SQL之 FORALL 語句
數組

 

1、BULK COLLECT批量綁定的示例 服務器

 
  1. --下面的示例中使用了BULK COLLECT將獲得的結果集綁定到記錄變量中        
  2. DECLARE  
  3.    TYPE emp_rec_type IS RECORD          --聲明記錄類型  
  4.    (  
  5.       empno      emp.empno%TYPE  
  6.      ,ename      emp.ename%TYPE  
  7.      ,hiredate   emp.hiredate%TYPE  
  8.    );  
  9.   
  10.    TYPE nested_emp_type IS TABLE OF emp_rec_type;  --聲明記錄類型變量   
  11.   
  12.    emp_tab   nested_emp_type;  
  13. BEGIN  
  14.    SELECT empno, ename, hiredate  
  15.    BULK   COLLECT INTO emp_tab       --使用BULK COLLECT 將所得的結果集一次性綁定到記錄變量emp_tab中  
  16.    FROM   emp;  
  17.   
  18.    FOR i IN emp_tab.FIRST .. emp_tab.LAST  
  19.    LOOP  
  20.       DBMS_OUTPUT.put_line('Current record is '||emp_tab(i).empno||chr(9)||emp_tab(i).ename||chr(9)||emp_tab(i).hiredate);  
  21.    END LOOP;  
  22. END;  
  23. --上面的例子能夠經過FOR 循環和普通的SELECT INTO來實現,那二者之間的差別呢?  
  24. --差別是FOR循環的SELECT INTO逐行提取並綁定到記錄變量,而BULK COLLECT則一次便可提取全部行並綁定到記錄變量。即謂批量綁定。  

2、使用LIMIT限制FETCH數據量
    在使用BULK COLLECT 子句時,對於集合類型,如嵌套表,聯合數組等會自動對其進行初始化以及擴展(以下示例)。所以若是使用BULK 
COLLECT子句操做集合,則無需對集合進行初始化以及擴展。因爲BULK COLLECT的批量特性,若是數據量較大,而集合在此時又自動擴展,爲避
免過大的數據集形成性能降低,所以使用limit子句來限制一次提取的數據量。limit子句只容許出如今fetch操做語句的批量中。
函數

    用法:
        FETCH ... BULK COLLECT INTO ... [LIMIT rows]
性能

 
  1. DECLARE  
  2.    CURSOR emp_cur IS  
  3.       SELECT empno, ename, hiredate FROM emp;  
  4.   
  5.    TYPE emp_rec_type IS RECORD  
  6.    (  
  7.       empno      emp.empno%TYPE  
  8.      ,ename      emp.ename%TYPE  
  9.      ,hiredate   emp.hiredate%TYPE  
  10.    );  
  11.   
  12.    TYPE nested_emp_type IS TABLE OF emp_rec_type;   -->定義了基於記錄的嵌套表  
  13.   
  14.    emp_tab     nested_emp_type;           -->定義集合變量,此時未初始化  
  15.    v_limit     PLS_INTEGER := 5;          -->定義了一個變量來做爲limit的值  
  16.    v_counter   PLS_INTEGER := 0;  
  17. BEGIN  
  18.    OPEN emp_cur;  
  19.   
  20.    LOOP  
  21.       FETCH emp_cur  
  22.       BULK   COLLECT INTO emp_tab         -->fetch時使用了BULK COLLECT子句  
  23.       LIMIT v_limit;                      -->使用limit子句限制提取數據量  
  24.   
  25.       EXIT WHEN emp_tab.COUNT = 0;        -->注意此時遊標退出使用了emp_tab.COUNT,而不是emp_cur%notfound  
  26.       v_counter   := v_counter + 1;       -->記錄使用LIMIT以後fetch的次數  
  27.   
  28.       FOR i IN emp_tab.FIRST .. emp_tab.LAST  
  29.       LOOP  
  30.          DBMS_OUTPUT.put_line( 'Current record is '||emp_tab(i).empno||CHR(9)||emp_tab(i).ename||CHR(9)||emp_tab(i).hiredate);  
  31.       END LOOP;  
  32.    END LOOP;  
  33.   
  34.    CLOSE emp_cur;  
  35.   
  36.    DBMS_OUTPUT.put_line( 'The v_counter is ' || v_counter );  
  37. END;  

3、RETURNING 子句的批量綁定
    BULK COLLECT除了與SELECT,FETCH進行批量綁定以外,還能夠與INSERT,DELETE,UPDATE語句結合使用。當與這幾個DML語句結合時,咱們
須要使用RETURNING子句來實現批量綁定。
fetch

 
  1. --下面示例中從表emp中刪除全部deptno=20的記錄  
  2. DECLARE  
  3.    TYPE emp_rec_type IS RECORD  
  4.    (  
  5.       empno      emp.empno%TYPE  
  6.      ,ename      emp.ename%TYPE  
  7.      ,hiredate   emp.hiredate%TYPE  
  8.    );  
  9.   
  10.    TYPE nested_emp_type IS TABLE OF emp_rec_type;  
  11.   
  12.    emp_tab   nested_emp_type;  
  13. --   v_limit   PLS_INTEGER := 3;  
  14. --   v_counter   PLS_INTEGER := 0;  
  15. BEGIN  
  16.    DELETE FROM emp  
  17.    WHERE  deptno = 20  
  18.    RETURNING empno, ename, hiredate     -->使用returning 返回這幾個列  
  19.    BULK   COLLECT INTO emp_tab;         -->將前面返回的列的數據批量插入到集合變量    
  20.   
  21.    DBMS_OUTPUT.put_line( 'Deleted ' || SQL%ROWCOUNT || ' rows.' );  
  22.    COMMIT;  
  23.      
  24.    IF emp_tab.COUNT > 0 THEN                 -->當集合變量不爲空時,輸出全部被刪除的元素  
  25.       FOR i IN emp_tab.FIRST .. emp_tab.LAST       
  26.       LOOP  
  27.          DBMS_OUTPUT.  
  28.           put_line(  
  29.                        'Current record  '  
  30.                     || emp_tab( i ).empno  
  31.                     || CHR( 9 )  
  32.                     || emp_tab( i ).ename  
  33.                     || CHR( 9 )  
  34.                     || emp_tab( i ).hiredate  
  35.                     || ' has been deleted' );  
  36.       END LOOP;  
  37.    END IF;  
  38. END;  

4、FORALL與BULK COLLECT 綜合運用
    FORALL與BULK COLLECT是實現批量SQL的兩個重要方式,咱們能夠將其結合使用以提升性能。下面的示例便是二者的總和運用。
spa

  1. DROP TABLE tb_emp;  
  2.   
  3. CREATE TABLE tb_emp AS                        -->建立表tb_emp  
  4.    SELECT empno, ename, hiredate  
  5.    FROM   emp  
  6.    WHERE  1 = 2;  
  7.   
  8. DECLARE                                 
  9.    CURSOR emp_cur IS                          -->聲明遊標   
  10.       SELECT empno, ename, hiredate FROM emp;  
  11.   
  12.    TYPE nested_emp_type IS TABLE OF emp_cur%ROWTYPE;  -->基於遊標的嵌套表類型  
  13.   
  14.    emp_tab   nested_emp_type;                         -->聲明嵌套變量  
  15. BEGIN  
  16.    SELECT empno, ename, hiredate  
  17.    BULK   COLLECT INTO emp_tab                        -->BULK  COLLECT批量提取數據  
  18.    FROM   emp  
  19.    WHERE  sal > 1000;  
  20.   
  21.    FORALL i IN 1 .. emp_tab.COUNT                     -->使用FORALL語句將變量中的數據插入到表tb_emp  
  22.       INSERT INTO (SELECT empno, ename, hiredate FROM tb_emp)  
  23.       VALUES emp_tab( i );  
  24.   
  25.    COMMIT;  
  26.    DBMS_OUTPUT.put_line( 'The total ' || emp_tab.COUNT || ' rows has been inserted to tb_emp' );  
  27. END;  

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

 

6、更多參考 對象

批量SQL之 FORALL 語句 blog

PL/SQL 集合的初始化與賦值
字符串

PL/SQL 聯合數組與嵌套表 
PL/SQL 變長數組
PL/SQL --> PL/SQL記錄 

SQL tuning 步驟

高效SQL語句必殺技

父遊標、子游標及共享遊標

綁定變量及其優缺點

dbms_xplan之display_cursor函數的使用

dbms_xplan之display函數的使用

執行計劃中各字段各模塊描述

使用 EXPLAIN PLAN 獲取SQL語句執行計劃

相關文章
相關標籤/搜索