Overview of PL/SQL Units

PL/SQL is a modern, block-structured programming language. It provides several features that make developing powerful database applications very convenient. For example, PL/SQL provides procedural constructs, such as loops and conditional statements, that are not available in standard SQL.

You can directly enter SQL data manipulation language (DML) statements inside PL/SQL blocks, and you can use subprograms supplied by Oracle to perform data definition language (DDL) statements.

PL/SQL code runs on the server, so using PL/SQL lets you centralize significant parts of your database applications for increased maintainability and security. It also enables you to achieve a significant reduction of network overhead in client/server applications.


Note:

Some Oracle tools, such as SQL Developer, contain a PL/SQL engine that lets you run PL/SQL locally.

You can even use PL/SQL for some database applications instead of 3GL programs that use embedded SQL or Oracle Call Interface (OCI).

PL/SQL units include:

Anonymous Blocks

An anonymous block is a PL/SQL unit that has no name. An anonymous block consists of an optional declarative part, an executable part, and one or more optional exception handlers.

The declarative part declares PL/SQL variables, exceptions, and cursors. The executable part contains PL/SQL code and SQL statements, and can contain nested blocks.

Exception handlers contain code that is invoked when the exception is raised, either as a predefined PL/SQL exception (such as NO_DATA_FOUND or ZERO_DIVIDE) or as an exception that you define.

Anonymous blocks are usually used interactively from a tool, such as SQL*Plus, or in a precompiler, OCI, or SQL*Module application. They are usually used to invoke stored subprograms or to open cursor variables.

The anonymous block in Example: Anonymous Block uses the DBMS_OUTPUT package to print the names of all employees in the HR.EMPLOYEES table who are in department 20.

Anonymous Block

DECLARE
  last_name  VARCHAR2(10);
  cursor     c1 IS
                SELECT LAST_NAME FROM EMPLOYEES
                WHERE DEPARTMENT_ID = 20;
BEGIN
  OPEN c1;
  LOOP
    FETCH c1 INTO last_name;
    EXIT WHEN c1%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(last_name);
  END LOOP;
END;
/

Result:

Hartstein
Fay

Exceptions let you handle Oracle Database error conditions with PL/SQL program logic, enabling your application to prevent the server from issuing an error that can cause the client application to end. The anonymous block in Example: Anonymous Block with Exception Handler for Predefined Error handles the predefined Oracle Database exception NO_DATA_FOUND (which results in ORA-01403 if not handled).

Anonymous Block with Exception Handler for Predefined Error

DECLARE
  Emp_number  INTEGER := 9999
  Emp_name    VARCHAR2(10);
BEGIN
  SELECT LAST_NAME INTO Emp_name
    FROM EMPLOYEES
      WHERE EMPLOYEE_ID = Emp_number;
  DBMS_OUTPUT.PUT_LINE('Employee name is ' || Emp_name);
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('No such employee: ' || Emp_number);
END;
/

Result:

No such employee: 9999

You can also define your own exceptions; that is, you can declare them in the declaration part of a block and define them in the exception part of the block, as in Example: Anonymous Block with Exception Handler for User-Defined Exception.

Anonymous Block with Exception Handler for User-Defined Exception

DECLARE
  Emp_name            VARCHAR2(10);
  Emp_number          INTEGER;
  Empno_out_of_range  EXCEPTION;
BEGIN
  Emp_number := 10001;
  IF Emp_number > 9999 OR Emp_number < 1000 THEN
    RAISE Empno_out_of_range;
  ELSE
    SELECT LAST_NAME INTO Emp_name
    FROM EMPLOYEES
    WHERE EMPLOYEE_ID = Emp_number;
    DBMS_OUTPUT.PUT_LINE('Employee name is ' || Emp_name);
 END IF;
EXCEPTION
  WHEN Empno_out_of_range THEN
    DBMS_OUTPUT.PUT_LINE('Employee number ' || Emp_number || 
      ' is out of range.');
END;
/

Result:

Employee number 10001 is out of range.

See Also:


Stored PL/SQL Units

A stored PL/SQL unit is a subprogram (procedure or function) or package that:

If a subprogram belongs to a package, it is called a package subprogram; if not, it is called a standalone subprogram.

Topics:

Naming Subprograms

Because a subprogram is stored in the database, it must be named. This distinguishes it from other stored subprograms and makes it possible for applications to invoke it. Each publicly-visible subprogram in a schema must have a unique name, and the name must be a legal PL/SQL identifier.


Note:

If you plan to invoke a stored subprogram using a stub generated by SQL*Module, then the stored subprogram name must also be a legal identifier in the invoking host 3GL language, such as Ada or C.

Subprogram Parameters

Stored subprograms can take parameters. In the procedure in Example: Stored Procedure with Parameters, the department number is an input parameter that is used when the parameterized cursor c1 is opened.

Stored Procedure with Parameters

CREATE OR REPLACE PROCEDURE get_emp_names (
  dept_num IN NUMBER
)
IS
  emp_name  VARCHAR2(10);
  CURSOR    c1 (dept_num NUMBER) IS
                SELECT LAST_NAME FROM EMPLOYEES
                WHERE DEPARTMENT_ID = dept_num;
BEGIN
  OPEN c1(dept_num);
  LOOP
    FETCH c1 INTO emp_name;
    EXIT WHEN C1%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(emp_name);
  END LOOP;
  CLOSE c1;
END;
/

The formal parameters of a subprogram have three major attributes, described in Table: Attributes of Subprogram Parameters.

Attributes of Subprogram Parameters

Parameter Attribute Description

Name

This must be a legal PL/SQL identifier.

Mode

This indicates whether the parameter is an input-only parameter (IN), an output-only parameter (OUT), or is both an input and an output parameter (IN OUT). If the mode is not specified, then IN is assumed.

Data Type

This is a standard PL/SQL data type.


Topics:

Parameter Modes

Parameter modes define the action of formal parameters. You can use the three parameter modes, IN (the default), OUT, and IN OUT, with any subprogram. Avoid using the OUT and IN OUT modes with functions. Good programming practice dictates that a function returns a single value and does not change the values of variables that are not local to the subprogram.

Table: Parameter Modes summarizes the information about parameter modes.

Parameter Modes

IN OUT IN OUT

The default.

Must be specified.

Must be specified.

Passes values to a subprogram.

Returns values to the caller.

Passes initial values to a subprogram; returns updated values to the caller.

Formal parameter acts like a constant.

Formal parameter acts like an uninitialized variable.

Formal parameter acts like an initialized variable.

Formal parameter cannot be assigned a value.

Formal parameter cannot be used in an expression; must be assigned a value.

Formal parameter must be assigned a value.

Actual parameter can be a constant, initialized variable, literal, or expression.

Actual parameter must be a variable.

Actual parameter must be a variable.



See Also:

Oracle Database PL/SQL Language Reference for details about parameter modes

Parameter Data Types

The data type of a formal parameter consists of one of these:

  • An unconstrained type name, such as NUMBER or VARCHAR2.

  • A type that is constrained using the %TYPE or %ROWTYPE attributes.


    Note:

    Numerically constrained types such as NUMBER(2) or VARCHAR2(20) are not allowed in a parameter list.

%TYPE and %ROWTYPE Attributes

Use the type attributes %TYPE and %ROWTYPE to constrain the parameter. For example, the procedure heading in Example: Stored Procedure with Parameters can be written as follows:

PROCEDURE get_emp_names(dept_num IN EMPLOYEES.DEPARTMENT_ID%TYPE)

This gives the dept_num parameter the same data type as the DEPARTMENT_ID column in the EMPLOYEES table. The column and table must be available when a declaration using %TYPE (or %ROWTYPE) is elaborated.

Using %TYPE is recommended, because if the type of the column in the table changes, it is not necessary to change the application code.

If the get_emp_names procedure is part of a package, you can use previously-declared public (package) variables to constrain its parameter data types. For example:

dept_number  NUMBER(2);
...
PROCEDURE get_emp_names(dept_num IN dept_number%TYPE);

Use the %ROWTYPE attribute to create a record that contains all the columns of the specified table. The procedure in Example: %TYPE and %ROWTYPE Attributes returns all the columns of the EMPLOYEES table in a PL/SQL record for the given employee ID.

%TYPE and %ROWTYPE Attributes

CREATE OR REPLACE PROCEDURE get_emp_rec (
  emp_number  IN  EMPLOYEES.EMPLOYEE_ID%TYPE,
  emp_info    OUT EMPLOYEES%ROWTYPE
)
IS
BEGIN
  SELECT * INTO emp_info
  FROM EMPLOYEES
  WHERE EMPLOYEE_ID = emp_number;
END;
/
 

Invoke procedure from PL/SQL block:

DECLARE
  emp_row  EMPLOYEES%ROWTYPE;
BEGIN
  get_emp_rec(206, emp_row);
  DBMS_OUTPUT.PUT('EMPLOYEE_ID: ' || emp_row.EMPLOYEE_ID);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('FIRST_NAME: ' || emp_row.FIRST_NAME);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('LAST_NAME: ' || emp_row.LAST_NAME);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('EMAIL: ' || emp_row.EMAIL);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('PHONE_NUMBER: ' || emp_row.PHONE_NUMBER);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('HIRE_DATE: ' || emp_row.HIRE_DATE);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('JOB_ID: ' || emp_row.JOB_ID);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('SALARY: ' || emp_row.SALARY);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('COMMISSION_PCT: ' || emp_row.COMMISSION_PCT);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('MANAGER_ID: ' || emp_row.MANAGER_ID);
  DBMS_OUTPUT.NEW_LINE;
  DBMS_OUTPUT.PUT('DEPARTMENT_ID: ' || emp_row.DEPARTMENT_ID);
  DBMS_OUTPUT.NEW_LINE;
END;
/

Result:

EMPLOYEE_ID: 206
FIRST_NAME: William
LAST_NAME: Gietz
EMAIL: WGIETZ
PHONE_NUMBER: 415.555.0100
HIRE_DATE: 07-JUN-94
JOB_ID: AC_ACCOUNT
SALARY: 8300
COMMISSION_PCT:
MANAGER_ID: 205
DEPARTMENT_ID: 110

Stored functions can return values that are declared using %ROWTYPE. For example:

FUNCTION get_emp_rec (dept_num IN EMPLOYEES.DEPARTMENT_ID%TYPE)
   RETURN EMPLOYEES%ROWTYPE IS ...

Tables and Records

You can pass PL/SQL tables as parameters to stored subprograms. You can also pass tables of records as parameters.


Note:

When passing a user defined type, such as a PL/SQL table or record to a remote subprogram, to make PL/SQL use the same definition so that the type checker can verify the source, you must create a redundant loop back DBLINK so that when the PL/SQL compiles, both sources pull from the same location.

Initial Parameter Values

Parameters can take initial values. Use either the assignment operator or the DEFAULT keyword to give a parameter an initial value. For example, these are equivalent:

PROCEDURE Get_emp_names (Dept_num IN NUMBER := 20) IS ...
PROCEDURE Get_emp_names (Dept_num IN NUMBER DEFAULT) IS ...

When a parameter takes an initial value, it can be omitted from the actual parameter list when you invoke the subprogram. When you do specify the parameter value on the invocation, it overrides the initial value.


Note:

Unlike in an anonymous PL/SQL block, you do not use the keyword DECLARE before the declarations of variables, cursors, and exceptions in a stored subprogram. In fact, it is an error to use it.

Creating Subprograms

Use a text editor to write the subprogram. Then, using an interactive tool such as SQL*Plus, load the text file containing the procedure by entering:

@get_emp

This loads the procedure into the current schema from the get_emp.sql file (.sql is the default file extension). The slash (/) after the code is not part of the code, it only activates the loading of the procedure.


Caution:

When developing a subprogram, it is usually preferable to use the statement CREATE OR REPLACE PROCEDURE or CREATE OR REPLACE FUNCTION. This statement replaces any previous version of that subprogram in the same schema with the newer version, but without warning.

You can use either the keyword IS or AS after the subprogram parameter list.


See Also:

Oracle Database SQL Language Reference for the syntax of the CREATE FUNCTION and CREATE PROCEDURE statements

Privileges Needed

To create a subprogram, a package specification, or a package body, you must meet these prerequisites:

  • You must have the CREATE PROCEDURE system privilege to create a subprogram or package in your schema, or the CREATE ANY PROCEDURE system privilege to create a subprogram or package in another user's schema. In either case, the package body must be created in the same schema as the package.


    Note:

    To create without errors (to compile the subprogram or package successfully) requires these additional privileges:
    • The owner of the subprogram or package must be explicitly granted the necessary object privileges for all objects referenced within the body of the code.

    • The owner cannot obtain required privileges through roles.


If the privileges of the owner of a subprogram or package change, then the subprogram must be reauthenticated before it is run. If a necessary privilege to a referenced object is revoked from the owner of the subprogram or package, then the subprogram cannot be run.

The EXECUTE privilege on a subprogram gives a user the right to run a subprogram owned by another user. Privileged users run the subprogram under the security domain of the owner of the subprogram. Therefore, users need not be granted the privileges to the objects referenced by a subprogram. This allows for more disciplined and efficient security strategies with database applications and their users. Furthermore, all subprograms and packages are stored in the data dictionary (in the SYSTEM tablespace). No quota controls the amount of space available to a user who creates subprograms and packages.


Note:

Package creation requires a sort. The user creating the package must be able to create a sort segment in the temporary tablespace with which the user is associated.

Altering Subprograms

To alter a subprogram, you must first drop it using the DROP PROCEDURE or DROP FUNCTION statement, then re-create it using the CREATE PROCEDURE or CREATE FUNCTION statement. Alternatively, use the CREATE OR REPLACE PROCEDURE or CREATE OR REPLACE FUNCTION statement, which first drops the subprogram if it exists, then re-creates it as specified.


Caution:

The subprogram is dropped without warning.

Dropping Subprograms and Packages

A standalone subprogram, a standalone function, a package body, or an entire package can be dropped using the SQL statements DROP PROCEDURE, DROP FUNCTION, DROP PACKAGE BODY, and DROP PACKAGE, respectively. A DROP PACKAGE statement drops both the specification and body of a package.

This statement drops the Old_sal_raise procedure in your schema:

DROP PROCEDURE Old_sal_raise;

Privileges Needed

To drop a subprogram or package, the subprogram or package must be in your schema, or you must have the DROP ANY PROCEDURE privilege. An individual subprogram within a package cannot be dropped; the containing package specification and body must be re-created without the subprograms to be dropped.

External Subprograms

A PL/SQL subprogram executing on an Oracle Database instance can invoke an external subprogram written in a third-generation language (3GL). The 3GL subprogram runs in a separate address space from that of the database.

PL/SQL Function Result Cache

Using the PL/SQL function result cache can save significant space and time. Each time a result-cached PL/SQL function is invoked with different parameter values, those parameters and their result are stored in the cache. Subsequently, when the same function is invoked with the same parameter values, the result is retrieved from the cache, instead of being recomputed. Because the cache is stored in a shared global area (SGA), it is available to any session that runs your application.

If a database object that was used to compute a cached result is updated, the cached result becomes invalid and must be recomputed.

The best candidates for result-caching are functions that are invoked frequently but depend on information that changes infrequently or never.

For more information about the PL/SQL function result cache, see Oracle Database PL/SQL Language Reference.

PL/SQL Packages

A package is a collection of related program objects (for example, subprogram, variables, constants, cursors, and exceptions) stored as a unit in the database.

Using packages is an alternative to creating subprograms as standalone schema objects. Packages have many advantages over standalone subprograms. For example, they:

  • Let you organize your application development more efficiently.

  • Let you grant privileges more efficiently.

  • Let you modify package objects without recompiling dependent schema objects.

  • Enable Oracle Database to read multiple package objects into memory at once.

  • Can contain global variables and cursors that are available to all subprograms in the package.

  • Let you overload subprograms. Overloading a subprogram means creating multiple subprograms with the same name in the same package, each taking arguments of different number or data type.


    See Also:

    Oracle Database PL/SQL Language Reference for more information about subprogram name overloading

The specification part of a package declares the public types, variables, constants, and subprograms that are visible outside the immediate scope of the package. The body of a package defines both the objects declared in the specification and private objects that are not visible to applications outside the package.

Example: Creating PL/SQL Package and Invoking Packaged Subprogram creates a package that contains one stored function and two stored procedures, and then invokes a procedure.

Creating PL/SQL Package and Invoking Packaged Subprogram

-- Sequence that packaged function needs:
 
CREATE SEQUENCE emp_sequence
START WITH 8000
INCREMENT BY 10;
 
-- Package specification:
 
CREATE or REPLACE PACKAGE employee_management IS
  FUNCTION hire_emp (
  firstname  VARCHAR2,
  lastname   VARCHAR2,
  email      VARCHAR2,
  phone      VARCHAR2,
  hiredate   DATE,
  job        VARCHAR2,
  sal        NUMBER,
  comm       NUMBER,
  mgr        NUMBER,
  deptno     NUMBER
) RETURN NUMBER;
 
 PROCEDURE fire_emp(
    emp_id IN NUMBER
 );
 
 PROCEDURE sal_raise (
    emp_id IN NUMBER,
    sal_incr IN NUMBER
 );
END employee_management;
/
 
-- Package body:
 
CREATE or REPLACE PACKAGE BODY employee_management IS
  FUNCTION hire_emp (
    firstname  VARCHAR2,
    lastname   VARCHAR2,
    email      VARCHAR2,
    phone      VARCHAR2,
    hiredate   DATE,
    job        VARCHAR2,
    sal        NUMBER,
    comm       NUMBER,
    mgr        NUMBER,
    deptno     NUMBER
  ) RETURN NUMBER
 IS
   new_empno  NUMBER(10);
 BEGIN
   new_empno := emp_sequence.NEXTVAL;
 
    INSERT INTO EMPLOYEES (
      employee_id,
      first_name,
      last_name,
      email,
      phone_number,
      hire_date,
      job_id,
      salary,
      commission_pct,
      manager_id,
      department_id
    )
    VALUES (
      new_empno,
      firstname,
      lastname,
      email,
      phone,
      hiredate,  
      job,
      sal, 
      comm,
      mgr,
      deptno
    );

   RETURN (new_empno);
 END hire_emp;
 
 PROCEDURE fire_emp (
   emp_id IN NUMBER
 ) IS
 BEGIN
   DELETE FROM EMPLOYEES
   WHERE EMPLOYEE_ID = emp_id;
 
   IF SQL%NOTFOUND THEN
     raise_application_error(
       -20011,
       'Invalid Employee Number: ' || TO_CHAR(Emp_id)
     );
   END IF;
 END fire_emp;
 
 PROCEDURE sal_raise (
    emp_id IN NUMBER,
    sal_incr IN NUMBER
  ) IS
  BEGIN
    UPDATE EMPLOYEES
    SET SALARY = SALARY + sal_incr
    WHERE EMPLOYEE_ID = emp_id;
 
    IF SQL%NOTFOUND THEN
      raise_application_error(
        -20011,
        'Invalid Employee Number: ' || TO_CHAR(Emp_id)
      );
    END IF;
  END sal_raise;
END employee_management;
/

Invoke packaged procedures:

DECLARE
  empno  NUMBER(6);
  sal    NUMBER(6);
  temp   NUMBER(6);
BEGIN
  empno := employee_management.hire_emp(
            'John',
            'Doe',
            'john.doe@company.com',
            '555-0100',
            '20-SEP-07',
            'ST_CLERK',
            2500,
            0,
            100,
            20);
 
  DBMS_OUTPUT.PUT_LINE('New employee ID is ' || TO_CHAR(empno));
END;
/

PL/SQL Object Size Limits

The size limit for PL/SQL stored database objects such as subprograms, triggers, and packages is the size of the Descriptive Intermediate Attributed Notation for Ada (DIANA) code in the shared pool in bytes. The Linux and UNIX limit on the size of the flattened DIANA/code size is 64K but the limit might be 32K on desktop platforms.

The most closely related number that a user can access is the PARSED_SIZE in the static data dictionary view *_OBJECT_SIZE. That gives the size of the DIANA in bytes as stored in the SYS.IDL_xxx$ tables. This is not the size in the shared pool. The size of the DIANA part of PL/SQL code (used during compilation) is significantly larger in the shared pool than it is in the system table.

Creating Packages

Each part of a package is created with a different statement. Create the package specification using the CREATE PACKAGE statement. The CREATE PACKAGE statement declares public package objects.

To create a package body, use the CREATE PACKAGE BODY statement. The CREATE PACKAGE BODY statement defines the procedural code of the public subprograms declared in the package specification.

You can also define private, or local, package subprograms, and variables in a package body. These objects can only be accessed by other subprograms in the body of the same package. They are not visible to external users, regardless of the privileges they hold.

It is often more convenient to add the OR REPLACE clause in the CREATE PACKAGE or CREATE PACKAGE BODY statements when you are first developing your application. The effect of this option is to drop the package or the package body without warning. The CREATE statements are:

CREATE OR REPLACE PACKAGE Package_name AS ...

and

CREATE OR REPLACE PACKAGE BODY Package_name AS ...

Creating Packaged Objects

The body of a package can contain:

  • Subprograms declared in the package specification.

  • Definitions of cursors declared in the package specification.

  • Local subprograms, not declared in the package specification.

  • Local variables.

Subprograms, cursors, and variables that are declared in the package specification are global. They can be invoked, or used, by external users that have EXECUTE permission for the package or that have EXECUTE ANY PROCEDURE privileges.

When you create the package body, ensure that each subprogram that you define in the body has the same parameters, by name, data type, and mode, as the declaration in the package specification. For functions in the package body, the parameters and the return type must agree in name and type.

Privileges to Needed to Create or Drop Packages

The privileges required to create or drop a package specification or package body are the same as those required to create or drop a standalone subprogram. See "Creating Subprograms" and "Dropping Subprograms and Packages".

Naming Packages and Package Objects

The names of a package and all public objects in the package must be unique within a given schema. The package specification and its body must have the same name. All package constructs must have unique names within the scope of the package, unless overloading of subprogram names is desired.

Package Invalidations and Session State

Each session that references a package object has its own instance of the corresponding package, including persistent state for any public and private variables, cursors, and constants. If any of the session's instantiated packages (specification or body) are invalidated, then all package instances in the session are invalidated and recompiled. Therefore, the session state is lost for all package instances in the session.

When a package in a given session is invalidated, the session receives ORA-04068 the first time it attempts to use any object of the invalid package instance. The second time a session makes such a package call, the package is reinstantiated for the session without error.


Note:

For optimal performance, Oracle Database returns this error message only once—each time the package state is discarded.

If you handle this error in your application, ensure that your error handling strategy can accurately handle this error. For example, when a subprogram in one package invokes a subprogram in another package, your application must be aware that the session state is lost for both packages.


In most production environments, DDL operations that can cause invalidations are usually performed during inactive working hours; therefore, this situation might not be a problem for end-user applications. However, if package invalidations are common in your system during working hours, then you might want to code your applications to handle this error when package calls are made.

Packages Supplied with Oracle Database

There are many packages provided with Oracle Database, either to extend the functionality of the database or to give PL/SQL access to SQL features. You can invoke these packages from your application.


See Also:

Oracle Product-Specific Packages for an overview of these Oracle Database packages

Overview of Bulk Binding

Oracle Database uses two engines to run PL/SQL blocks and subprograms. The PL/SQL engine runs procedural statements, while the SQL engine runs SQL statements. During execution, every SQL statement causes a context switch between the two engines, resulting in performance overhead.

Performance can be improved substantially by minimizing the number of context switches required to run a particular block or subprogram. When a SQL statement runs inside a loop that uses collection elements as bind variables, the large number of context switches required by the block can cause poor performance. Collections include:

  • Varrays

  • Nested tables

  • Index-by tables

  • Host arrays

Binding is the assignment of values to PL/SQL variables in SQL statements. Bulk binding is binding an entire collection at once. Bulk binds pass the entire collection back and forth between the two engines in a single operation.

Typically, using bulk binds improves performance for SQL statements that affect four or more database rows. The more rows affected by a SQL statement, the greater the performance gain from bulk binds.


Note:

This section provides an overview of bulk binds to help you decide whether to use them in your PL/SQL applications. For detailed information about using bulk binds, including ways to handle exceptions that occur in the middle of a bulk bind operation, see Oracle Database PL/SQL Language Reference.

Parallel DML is disabled with bulk binds.


When to Use Bulk Binds

Consider using bulk binds to improve the performance of:

DML Statements that Reference Collections

A bulk bind, which uses the FORALL keyword, can improve the performance of INSERT, UPDATE, or DELETE statements that reference collection elements.

The PL/SQL block in Example: DML Statements that Reference Collections increases the salary for employees whose manager's ID number is 7902, 7698, or 7839, with and without bulk binds. Without bulk bind, PL/SQL sends a SQL statement to the SQL engine for each updated employee, leading to context switches that slow performance.

DML Statements that Reference Collections

DECLARE
  2    TYPE numlist IS VARRAY (100) OF NUMBER;
  3    id NUMLIST := NUMLIST(7902, 7698, 7839);
BEGIN
  -- Efficient method, using bulk bind:
  
  FORALL i IN id.FIRST..id.LAST
  UPDATE EMPLOYEES
  SET SALARY = 1.1 * SALARY
  WHERE MANAGER_ID = id(i);
 
 -- Slower method:
 
 FOR i IN id.FIRST..id.LAST LOOP
    UPDATE EMPLOYEES
    SET SALARY = 1.1 * SALARY
    WHERE MANAGER_ID = id(i);
 END LOOP;
END;
/

SELECT Statements that Reference Collections

The BULK COLLECT INTO clause can improve the performance of queries that reference collections. You can use BULK COLLECT INTO with tables of scalar values, or tables of %TYPE values.

The PL/SQL block in Example: SELECT Statements that Reference Collections queries multiple values into PL/SQL tables, with and without bulk binds. Without bulk bind, PL/SQL sends a SQL statement to the SQL engine for each selected employee, leading to context switches that slow performance.

SELECT Statements that Reference Collections

DECLARE
  TYPE var_tab IS TABLE OF VARCHAR2(20)
  INDEX BY PLS_INTEGER;
  
  empno    VAR_TAB;
  ename    VAR_TAB;
  counter  NUMBER;
  
  CURSOR c IS
    SELECT EMPLOYEE_ID, LAST_NAME
    FROM EMPLOYEES
    WHERE MANAGER_ID = 7698;
BEGIN
 -- Efficient method, using bulk bind:
 
 SELECT EMPLOYEE_ID, LAST_NAME BULK COLLECT
 INTO empno, ename
 FROM EMPLOYEES
 WHERE MANAGER_ID = 7698;
 
 -- Slower method:
 
 counter := 1;
 
 FOR rec IN c LOOP
    empno(counter) := rec.EMPLOYEE_ID;
    ename(counter) := rec.LAST_NAME;
    counter := counter + 1;
 END LOOP;
END;
/

FOR Loops that Reference Collections and Return DML

You can use the FORALL keyword with the BULK COLLECT INTO keywords to improve the performance of FOR loops that reference collections and return DML.

The PL/SQL block in Example: FOR Loops that Reference Collections and Return DML updates the EMPLOYEES table by computing bonuses for a collection of employees. Then it returns the bonuses in a column called bonus_list_inst. The actions are performed with and without bulk binds. Without bulk bind, PL/SQL sends a SQL statement to the SQL engine for each updated employee, leading to context switches that slow performance.

FOR Loops that Reference Collections and Return DML

DECLARE
  TYPE emp_list IS VARRAY(100) OF EMPLOYEES.EMPLOYEE_ID%TYPE;
  empids emp_list := emp_list(182, 187, 193, 200, 204, 206);
  
  TYPE bonus_list IS TABLE OF EMPLOYEES.SALARY%TYPE;
  bonus_list_inst  bonus_list;
  
BEGIN
  -- Efficient method, using bulk bind:
 
 FORALL i IN empids.FIRST..empids.LAST
 UPDATE EMPLOYEES
 SET SALARY = 0.1 * SALARY
 WHERE EMPLOYEE_ID = empids(i)
 RETURNING SALARY BULK COLLECT INTO bonus_list_inst;
 
 -- Slower method:
 
 FOR i IN empids.FIRST..empids.LAST LOOP
   UPDATE EMPLOYEES
   SET SALARY = 0.1 * SALARY
   WHERE EMPLOYEE_ID = empids(i)
   RETURNING SALARY INTO bonus_list_inst(i);
 END LOOP;
END;
/

Triggers

A trigger is a special kind of PL/SQL anonymous block. You can define triggers to fire before or after SQL statements, either on a statement level or for each row that is affected. You can also define INSTEAD OF triggers or system triggers (triggers on DATABASE and SCHEMA).


See Also:

Oracle Database PL/SQL Language Reference for more information about triggers