PL/SQLintermediate

Bulk Operations: BULK COLLECT and FORALL

Explain how to optimize PL/SQL performance for large data volumes using bulk binding techniques

BULK COLLECT and FORALL are PL/SQL constructs that dramatically reduce context switches between the PL/SQL engine and the SQL engine, which is the single biggest performance killer in row-by-row ('slow-by-slow') processing. Instead of looping through a cursor one row at a time and issuing individual DML statements, these constructs batch operations, sending an entire collection to the SQL engine in one round trip.

Row-by-row processing is like a waiter carrying one plate at a time from the kitchen to the dining room for a 200-guest banquet — hugely inefficient. BULK COLLECT and FORALL are like using a large catering cart to move dozens of plates in a single trip.

Key Concepts

1
BULK COLLECT INTO fetches multiple rows from a query directly into a PL/SQL collection (associative array, nested table, or VARRAY) in a single fetch, rather than looping with FETCH ... INTO row by row. FORALL does the inverse for DML: it takes a collection and issues the INSERT/UPDATE/DELETE for every element in a single batch, still executing individual DML statements under the hood but eliminating the context-switch overhead of a PL/SQL loop wrapping each one.
BULK COLLECT INTOFETCH ... INTOFORALL
2
In EBS customizations — like a custom program processing tens of thousands of interface rows or applying corrections across large transaction sets — using BULK COLLECT with the LIMIT clause (to avoid consuming excessive PGA memory) combined with FORALL is considered a baseline professional practice. Oracle's own interface import programs use these techniques internally for this reason.
LIMIT
3
Interviewers commonly ask candidates to rewrite a naive row-by-row cursor loop using BULK COLLECT/FORALL, and to explain the SAVE EXCEPTIONS clause, which allows a FORALL statement to continue processing remaining rows even if some individual DML statements fail, collecting all errors into SQL%BULK_EXCEPTIONS for later review.
SAVE EXCEPTIONSSQL%BULK_EXCEPTIONS