How to use ForAll and bulk collect:
1. Using ForAll is more efficient than for, because the former switches only once to the context, while the latter switches between multiple contexts in the same number of cycles.
2. Using Bluk collect to fetch a data collection at once is more efficient than using a cursor bar, especially if the network is not very good. But Bluk collect requires a lot of memory.
Example:
SQL code
- Create table Test_forall (user_id number (ten), user_name VARCHAR2 (20));
SELECT INTO using bulk collect
SQL code
- DECLARE
- TYPE table_forall is table of Test_forall%rowtype;
- V_table Table_forall;
- BEGIN
- SELECT Mub.user_id,mub.user_name
- BULK COLLECT into v_table
- From mag_user_basic Mub
- WHERE mub.user_id between 10000 and 10100;
- FORALL idx in 1..v_table. COUNT
- INSERT into test_forall VALUES v_table (IDX);
- --values (v_table (IDX). user_id,v_table (IDX). user_name); Error
- -in PL/SQL, BULK In-bind and Record,%rowtype cannot be used in one piece,
- -in other words, BULK in-bind can only be used with arrays of simple types
- COMMIT;
- EXCEPTION
- When OTHERS Then
- ROLLBACK;
- END;
fetch into uses bulk collect
SQL code
- DECLARE
- TYPE table_forall is table of Test_forall%rowtype;
- V_table Table_forall;
- CURSOR C1 is
- SELECT Mub.user_id,mub.user_name
- From mag_user_basic Mub
- WHERE mub.user_id between 10000 and 10100;
- BEGIN
- OPEN C1;
- --use bulk collect in fetch into
- FETCH C1 BULK COLLECT into v_table;
- FORALL idx in 1..v_table. COUNT
- INSERT into test_forall VALUES v_table (IDX);
- COMMIT;
- EXCEPTION
- When OTHERS Then
- ROLLBACK;
- END;
use bulk collect in returning into
SQL code
- CREATE TABLE test_forall2 as SELECT * from Test_forall;
- ----using bulk collect in returning into
- DECLARE
- TYPE idlist is TABLE of Test_forall. User_id%type;
- Enums idlist;
- TYPE namelist is TABLE of Test_forall.user_name%type;
- Names NameList;
- BEGIN
- DELETE from test_forall2 WHERE user_id = 10100
- Returning user_id, user_name BULK COLLECT into enums, names;
- Dbms_output.put_line (' Deleted ' | | Sql%rowcount | | ' rows: ');
- For i in enums. First: Enums. Last
- LOOP
- Dbms_output.put_line (' User # ' | | | enums (i) | | ': ' | | | names (i));
- END LOOP;
- COMMIT;
- EXCEPTION
- When OTHERS Then
- ROLLBACK;
- END;
in a batch update, change the for to ForAll
SQL code
- DECLARE
- TYPE Numlist is Varray (a) of number ;
- Depts numlist: = Numlist (10, 30, 70, ...);
- --Department numbers
- BEGIN
- ...
- For i in depts.first. Depts. Last
- LOOP
- ...
- --update statement is sent to the SQL engine
- --With all iteration of the for loop!
- UPDATE emp SET sal = sal * 1.10 WHERE deptno = depts (i);
- END LOOP:
- END;
SQL code
- --update statement is sent to the sql engine just once, with the entire nested table
- forall i in depts.first. Depts.last
- update emp set sal = sal * 1.10 where deptno = depts (i);
To maximize performance, rewrite your programs as follows:
A. If an INSERT, UPDATE, or DELETE statement executes inside a loop and References collection elements, move it to a for All statement.
B. If a SELECT into, FETCH into, or returning into clause references a
Collection, incorporate the BULK COLLECT clause.
C. If possible, use host arrays to pass collections back and forth between your Programs and the database server.
D. If the failure of a DML operation on a particular row are not a serious problem,include the keywords SAVE EXCEPTIONS in The FORALL statement and report Or clean up the errors in a subsequent loop using the%bulk_exceptions Attribute.
Oracle Bulk Bind ForAll and bulk COLLECT