Consider a program to populate elements of a PL/SQL collection from a SELECT query thus
declare
type employee_ids_t is table of employees.employee_id%type
index by binary_integer;
employee_ids employee_ids_t; n integer:=0;
begin
for j in ( select employee_id from employees where salary < 3000 )
loop
n := n+1; employee_ids(n) := j.employee_id;
end loop;
end;
Each explicit row by row assignment of the collection element to the cursor component causes a context switch between the PL/SQL engine and the SQL engine resulting in performance overhead. The following formulation (one of a family of constructs generically referred to as bulk binding and available pre-Oracle9i)
declare
type employee_ids_t is table of employees.employee_id%type
index by binary_integer;
employee_ids employee_ids_t; n integer:=0;
begin
select employee_id
bulk collect into employee_ids
from employees where salary < 3000;
end;
substantially improves performance by minimizing the number of context switches required to execute the block. (The above fragments work pre-Oracle 9i.)
There are many application implementation situations that require dynamic SQL. Native dynamic SQL (execute immediate and related constructs) is usually preferred over Dbms_Sql because it's easier to write and proof read and executes faster. However, pre-Oracle9i, only Dbms_Sql could be used for dynamic bulk binding. Oracle9i introduces the following syntax for bulk binding in native dynamic SQL
declare
type employee_ids_t is table of employees.employee_id%type
index by binary_integer;
employee_ids employee_ids_t; n integer:=0;
begin /* new at 9i */
execute immediate 'select employee_id from employees where salary < 3000'
bulk collect into employee_ids;
end;