Difference between Bulk collect and Forall.

Bulk collect: is a CLAUSE. is used to fetch the records from the cursor.
Forall: is a STATEMENT. is used to do dml operation of fetched records.
The body of the FORALL statement is a single DML statement -- an INSERT, UPDATE, or DELETE.

BULK COLLECT is:

"The keywords BULK COLLECT tell the SQL engine to bulk-bind output collections before returning them to the PL/SQL engine. You can use these keywords in the SELECT
INTO, FETCH INTO, and RETURNING INTO clauses.

Here is the syntax:

... BULK COLLECT INTO collection_name[, collection_name] ..."
and FORALL is defined as

FORALL is:

"The keyword FORALL instructs the PL/SQL engine to bulk-bind input collections before sending them to the SQL engine. Although the FORALL statement contains an
iteration scheme, it is not a FOR loop.

Its syntax follows:

FORALL index IN lower_bound..upper_bound
   sql_statement;

The index can be referenced only within the FORALL statement and only as a collection subscript. The SQL statement must be an INSERT, UPDATE, or DELETE statement that
references collection elements. And, the bounds must specify a valid range of consecutive index numbers. The SQL engine executes the SQL statement once for each index
number in the range."

So there you go. Collections, BULK COLLECT and FORALL are the new features in Oracle 8i, 9i and 10g PL/SQL that can really make a different to you PL/SQL performance.
Hopefully, if you've not come across these areas before.
----------------------------------------------------------------------------

BULK COLLECT Syntax & Example:

FETCH BULK COLLECT BULK COLLECT INTO
LIMIT ;

set timing on
DECLARE
  CURSOR a_cur IS
 SELECT program_id
  FROM airplanes;
BEGIN
   FOR cur_rec IN a_cur LOOP
     NULL;
   END LOOP;
END;
 /
DECLARE
  CURSOR a_cur IS
 SELECT program_id
  FROM airplanes;
  TYPE myarray IS TABLE OF a_cur%ROWTYPE;
  cur_array myarray;
BEGIN
   OPEN a_cur;
   LOOP
     FETCH a_cur BULK COLLECT INTO cur_array LIMIT 100;
     EXIT WHEN a_cur%NOTFOUND;
   END LOOP;
   CLOSE a_cur;
END;
 /
DECLARE
  CURSOR a_cur IS
 SELECT program_id
  FROM airplanes;
  TYPE myarray IS TABLE OF a_cur%ROWTYPE;
  cur_array myarray;
BEGIN
   OPEN a_cur;
   LOOP
     FETCH a_cur BULK COLLECT INTO cur_array LIMIT 500;
     EXIT WHEN a_cur%NOTFOUND;
   END LOOP;
   CLOSE a_cur;
END;
 /
DECLARE
  CURSOR a_cur IS
 SELECT program_id
  FROM airplanes;
  TYPE myarray IS TABLE OF a_cur%ROWTYPE;
  cur_array myarray;
BEGIN
   OPEN a_cur;
   LOOP
     FETCH a_cur BULK COLLECT INTO cur_array LIMIT 1000;
     EXIT WHEN a_cur%NOTFOUND;
   END LOOP;
   CLOSE a_cur;
END;
 /
-- try with a LIMIT clause of 2500, 5000, and 10000. What do you see?
----------------------------------------------------------------------------

FORALL Syntax & Example:

FORALL IN ..
 
 SAVE EXCEPTIONS;

FORALL IN INDICES OF
 [BETWEEN AND ]
 
 SAVE EXCEPTIONS;

FORALL IN INDICES OF
VALUES OF
 
 SAVE EXCEPTIONS;


FOR INSERT
===========

CREATE TABLE servers2 AS
SELECT *
FROM servers
WHERE 1=2;
DECLARE
  CURSOR s_cur IS
 SELECT *
  FROM servers;
  TYPE fetch_array IS TABLE OF s_cur%ROWTYPE;
  s_array fetch_array;
BEGIN
   OPEN s_cur;
   LOOP
     FETCH s_cur BULK COLLECT INTO s_array LIMIT 1000;
     FORALL i IN 1..s_array.COUNT
     INSERT INTO servers2 VALUES s_array(i);
     EXIT WHEN s_cur%NOTFOUND;
   END LOOP;
   CLOSE s_cur;
   COMMIT;
END;
 /

FOR UPDATE
===========

SELECTDISTINCT srvr_id
FROM servers2
ORDER BY 1;
DECLARE
  TYPE myarray IS TABLE OF servers2.srvr_id%TYPE
  INDEX BY BINARY_INTEGER;
  d_array myarray;
BEGIN
   d_array(1) := 608;
   d_array(2) := 610;
   d_array(3) := 612;
   FORALL i IN d_array.FIRST .. d_array.LAST
   UPDATE servers2
   SET srvr_id = 0
   WHERE srvr_id = d_array(i);
   COMMIT;
END;
 /
SELECT srvr_id
FROM servers2
WHERE srvr_id = 0;

FOR DELETE
============

set serveroutput on
DECLARE
  TYPE myarray IS TABLE OF servers2.srvr_id%TYPE
  INDEX BY BINARY_INTEGER;
  d_array myarray;
BEGIN
   d_array(1) := 614;
   d_array(2) := 615;
   d_array(3) := 616;
   FORALL i IN d_array.FIRST .. d_array.LAST
   DELETE servers2
   WHERE srvr_id = d_array(i);
   COMMIT;
   FOR i IN d_array.FIRST .. d_array.LAST LOOP
     dbms_output.put_line('Iteration #' || i || ' deleted ' ||
     SQL%BULK_ROWCOUNT(i) || ' rows.');
   END LOOP;
END;
 /
SELECT srvr_id
FROM servers2
WHERE srvr_id IN (614, 615, 616);

Comments