Functions vs procedures in Oracle Functions vs procedures in Oracle oracle oracle

Functions vs procedures in Oracle


The difference is- A function must return a value (of any type) by default definition of it, whereas in case of a procedure you need to use parameters like OUT or IN OUT parameters to get the results. You can use a function in a normal SQL where as you cannot use a procedure in SQL statements.

Some Differences between Functions and Procedures

  1. A function always returns a value using the return statement while a procedure may return one or more values through parameters or may not return at all.Although, OUT parameters can still be used in functions, they are not advisable neither are there cases where one might find a need to do so. Using OUT parameter restricts a function from being used in a SQL Statement.

  2. Functions can be used in typical SQL statements like SELECT, INSERT, UPDATE, DELETE, MERGE, while procedures can't.

  3. Functions are normally used for computations where as procedures are normally used for executing business logic.

  4. Oracle provides the provision of creating "Function Based Indexes" to improve the performance of the subsequent SQL statement. This applies when performing the function on an indexed column in where clause of a query.

More Information on Functions Vs. Procedures here and here.


There is almost never a performance difference between procedures and functions.

In a few extremely rare cases:

  • A procedure IN OUT argument is faster than a function return, when inlining is enabled.
  • A procedure IN OUT argument is slower than a function return, when inlining is disabled.

Test code

--Run one of these to set optimization level:--alter session set plsql_optimize_level=0;--alter session set plsql_optimize_level=1;--alter session set plsql_optimize_level=2;--alter session set plsql_optimize_level=3;--Run this to compare times.  Move the comment to enable the procedure or the function.declare    v_result varchar2(4000);    procedure test_procedure(p_result in out varchar2) is    begin        p_result := '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';    end;    function test_function return varchar2 is    begin        return '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';    end;begin    for i in 1 .. 10000000 loop        --Comment out one of these lines to change the test.        --test_procedure(v_result);        v_result := test_function;    end loop;end;/

Results

Inlining enabled:  PLSQL_OPTIMIZE_LEVEL = 2 (default) or 3Function  run time in seconds: 2.839, 2.933, 2.979Procedure run time in seconds: 1.685, 1.700, 1.762Inlining disabled: PLSQL_OPTIMIZE_LEVEL = 0 or 1Function  run time in seconds:  5.164, 4.967, 5.632Procedure run time in seconds: 6.1, 6.006, 6.037

The above code is trivial and perhaps subject to other optimizations. But I have seen similar results with production code.

Why the difference doesn't matter

Don't look at the above test and think "a procedure runs twice as fast as a function!". Yes, the overhead of a function is almost twice as much as the overhead of a procedure. But either way, the overhead is irrelevantly small.

The key to database performance is to do as much work as possible in SQL statements, in batches. If a program calls a function or procedure ten million times per second then that program has serious design problems.


State-changing vs non-state-changing

On top of Romo Daneghyan's answer, I've always viewed the difference as their behaviour on the program state. That is, conceptually,

  • Procedures can change some state, either of the parameters or of the environment (eg, data in tables etc).
  • Functions do not change state, and you would expect that calling a particular function would not modify any data/state. (Ie, the concept underlying functional programming)

Ie, if you called a function named generateId(...), you'd expect it to only do some computation and return a value. But calling a procedure generateId ..., you might expect it to change values in some tables.

Of course, it seems like in Oracle as well as many languages, this does not apply and is not enforced, so perhaps it's just me.