BULK COLLECT 子句會批量檢索結果,即一次性將結果集綁定到一個集合變量中,並從SQL引擎發送到PL/SQL引擎。一般能夠在SELECT INTO、
FETCH INTO以及RETURNING INTO子句中使用BULK COLLECT。本文將逐一描述BULK COLLECT在這幾種情形下的用法。
有關FORALL語句的用法請參考:批量SQL之 FORALL 語句 數組
1、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則一次便可提取全部行並綁定到記錄變量。即謂批量綁定。
2、使用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;
3、RETURNING 子句的批量綁定
BULK COLLECT除了與SELECT,FETCH進行批量綁定以外,還能夠與INSERT,DELETE,UPDATE語句結合使用。當與這幾個DML語句結合時,咱們
須要使用RETURNING子句來實現批量綁定。 fetch
- --下面示例中從表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;
4、FORALL與BULK COLLECT 綜合運用
FORALL與BULK COLLECT是實現批量SQL的兩個重要方式,咱們能夠將其結合使用以提升性能。下面的示例便是二者的總和運用。 spa
- DROP TABLE tb_emp;
-
- CREATE TABLE tb_emp AS -->建立表tb_emp
- SELECT empno, ename, hiredate
- FROM emp
- WHERE 1 = 2;
-
- DECLARE
- CURSOR emp_cur IS -->聲明遊標
- SELECT empno, ename, hiredate FROM emp;
-
- TYPE nested_emp_type IS TABLE OF emp_cur%ROWTYPE; -->基於遊標的嵌套表類型
-
- emp_tab nested_emp_type; -->聲明嵌套變量
- BEGIN
- SELECT empno, ename, hiredate
- BULK COLLECT INTO emp_tab -->BULK COLLECT批量提取數據
- FROM emp
- WHERE sal > 1000;
-
- FORALL i IN 1 .. emp_tab.COUNT -->使用FORALL語句將變量中的數據插入到表tb_emp
- INSERT INTO (SELECT empno, ename, hiredate FROM tb_emp)
- VALUES emp_tab( i );
-
- COMMIT;
- DBMS_OUTPUT.put_line( 'The total ' || emp_tab.COUNT || ' rows has been inserted to tb_emp' );
- 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語句執行計劃