PL/SQL batch statement (1) BULK COLLECT

We know that running SQL statements in a PL/SQL program is expensive, because SQL statements are submitted to the SQL engine for processing. This control transfer between the PL/SQL engine and the SQL engine is called context switching, which is changed every time , there is additional overhead.
However, FORALL and BULK COLLECT allow the PL/SQL engine to compress multiple contexts into one, which drastically reduces the execution time of SQL statements that process multiple rows of records in PL/SQL.
      

          

Example:
1. BULK COLLECT binds the result set at one time (all)

--The following example uses BULK COLLECT to bind the result set to the record variable        
DECLARE
   TYPE emp_rec_type IS RECORD   -- declare record type
   (
      empno      emp.empno%TYPE
     ,ename      emp.ename%TYPE
     , hiredate emp.hiredate % TYPE
   );

   TYPE nested_emp_type IS TABLE OF emp_rec_type;   -- declare record type variable
   emp_tab   nested_emp_type;
BEGIN SELECT empno, ename, hiredate BULK COLLECT INTO emp_tab --Use
BULK COLLECT to bind the result set to the record variable emp_tab at one time 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;
--The above example can be implemented by a FOR loop and a normal SELECT INTO, what's the difference between the two? --The difference is that the FOR loop's SELECT INTO fetches row by row and binds to the record variable, while the BULK COLLECT fetches all rows at once and binds to the record variable. This is called batch binding.

 




2. Use LIMIT to limit the amount of FETCH data (limit number)
When using the BULK COLLECT clause, collection types, such as nested tables, associative arrays, etc., will be automatically initialized and expanded (the following example). Therefore, if you use the BULK COLLECT clause to operate on a collection, there is no need to initialize and expand the collection. Due to the batch nature of BULK COLLECT, if the amount of data is large, and the collection is automatically expanded at this time, in order to avoid performance degradation caused by an excessively large data set, the limit clause is used to limit the amount of data extracted at one time. The limit clause is only allowed in batches of fetch statements.
Usage:
    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;    --> defines a record-based nested table
   emp_tab nested_emp_type;            --> Define the set variable, 
v_limit PLS_INTEGER :
= 5 is not initialized at this time; --> Define a variable as the value of limit v_counter PLS_INTEGER : = 0 ; BEGIN OPEN emp_cur; LOOP FETCH emp_cur BULK COLLECT INTO emp_tab --> The BULK COLLECT clause LIMIT v_limit is used when fetching; --> The limit clause is used to limit the amount of data extracted EXIT WHEN emp_tab.COUNT = 0 ; --> Note that the cursor exits using emp_tab.COUNT instead of emp_cur% notfound v_counter : = v_counter + 1 ; --> record the number of fetches after using LIMIT 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. Batch binding using RETURNING clause
    BULK COLLECT can be combined with INSERT, DELETE and UPDATE statements in addition to batch binding with SELECT and FETCH. When combined with these several DML statements, we
need to use the RETURNING clause to achieve bulk binding.

--In the following example, delete all records with deptno=20 from table emp
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 --> use returning to return these columns BULK COLLECT INTO emp_tab; --> Insert the data of the previously returned column into the collection variable in batches DBMS_OUTPUT.put_line( 'Deleted ' || SQL%ROWCOUNT || ' rows.' ); COMMIT; IF emp_tab.COUNT > 0 THEN --> When the set variable is not empty, output all deleted elements 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. Limitations of BULK COLLECT
1. The BULK COLLECT clause cannot be used for associative arrays that use string types as keys.
2. BULK COLLECT can only be used in server-side programs. If it is used in client-side programs, it will generate an error that does not support this feature.
3. The target object of BULK COLLECT INTO must be a collection type.
4. Compound targets (such as object types) cannot be used in the RETURNING INTO clause.
5. Multiple compound targets cannot be used in the BULK COLLECT INTO clause if there are multiple implicit data type conversions.
6. If there is an implicit data type conversion, a collection of composite targets (such as a collection of object types) cannot be used in the BULK COLLECTINTO clause.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325141848&siteId=291194637