Sie sind auf Seite 1von 35

High

Performance PL/SQL
Steven Feuerstein
Architect
Oracle CorporaGon
February 2015

Please Stand By. This session will begin promptly at


the 8me indicated on the agenda. Thank You.
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Safe Harbor Statement


The following is intended to outline our general product direcGon. It is intended for
informaGon purposes only, and may not be incorporated into any contract. It is not a
commitment to deliver any material, code, or funcGonality, and should not be relied upon
in making purchasing decisions. The development, release, and Gming of any features or
funcGonality described for Oracles products remains at the sole discreGon of Oracle.

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

High Performance PL/SQL Agenda


The funcGon result cache
BULK COLLECT and FORALL
NOCOPY hint
The UDF pragma, new to Oracle Database 12c


All referenced code is available in my demo.zip le from the
PL/SQL Learning Library: oracle.com/oll/plsql.
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

PL/SQL Run8me Memory Architecture


System Global Area (SGA) of RDBMS Instance
Shared Pool
Reserved Pool

Large Pool

Session 1

emp_rec emp%rowtype;
tot_tab pkg.tottabtype;

Session 1 memory
UGA User Global Area
PGA Process Global Area

Library cache
Shared SQL
Pre-parsed

calc_totals

Select *
from emp

Update emp
Set sal=...

show_emps

upd_salaries

emp_rec emp%rowtype;
tot_tab pkg.tottabtype;

Session 2 memory
UGA User Global Area
PGA Process Global Area
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Session 2

Data Caching Op8ons in PL/SQL


Caching is a Gme-honored technique for improving performance.
Store data that doesnt change for some period of +me in a locaGon that can be
accessed more quickly than the source.
The SGA is an enormous, complex cache for an enGre database instance.

DeterminisGc funcGons
Under some circumstances, can avoid execuGon of funcGon with matching inputs

PGA caching using package-level variables


Very fast, but per-session cache, only for staGc datasets, inapplicable to stateless
environments like the Internet.

The funcGon result cache


The most powerful and widely applicable caching technique for PL/SQL funcGons
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

The Func8on Result Cache


This cache is stored in the SGA, rather than PGA.
It is shared across sessions connected to instance, so it scales well.

Oracle automaGcally invalidates any caches that contain


possibly dirty data.
You can use and should use it to retrieve data from any table
that is queried more frequently than updated.
And the same rows are being fetched repeatedly.

Available in Enterprise EdiGon only.


You can include the FRC syntax in code running in Standard EdiGon; the
feature will simply be ignored.
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

How the Func8on Result Cache Works


Add the RESULT_CACHE clause to your funcGon's header.
That's it! Truly minimal impact on code if you've "hidden" SELECTS in funcGon.

When a call is made to funcGon, Oracle compares argument values (must


be IN only) to the cache.
If no match, the funcGon is executed and the inputs and return data are
cached.
If a match is found, the funcGon is not executed; cached data is returned.
If changes to a "relies on" table are commiied, the cache is marked
invalid and will be re-built.
11g_frc_demo.sql
11g_frc_encapsulation.sql
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Performance Impact of Result Cache


The result cache is stored in the SGA.
So we should expect it be slower than a PGA-based cache.
But accessing result cache data does not require going through
the SQL engine.
So it should be much faster than execuGng a query.
Even if the statement is parsed and the data blocks are already in the SGA.


sf_timer.*
11g_emplu.pkg
11g_emplu_test.sql
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Result Cache Things to Keep in Mind - 1


If you have uncommiied changes in your session, dependent caches are
ignored.
The cache will not override your own changed data.

Caching is not performed for complex types: records with CLOBs,


collecGons, etc.
But Oracle is opGmisGc!

The cache is not related to SQL statements in your funcGon.


It only keeps track of the input values and the RETURN clause data.
11g_frc_demo.sql

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Result Cache Things to Keep in Mind - 2


You cannot use the result cache with invoker rights program units unGl
12.1.
Bypass execuGon of funcGon body, Oracle cannot resolve references to objects - the
whole point of IR.

FuncGons with session-specic dependencies must be "result-cached" with


great care.
Virtual private database conguraGons
References to SYSDATE, reliance on NLS_DATE_FORMAT, Gme zone changes
ApplicaGon contexts (calls to SYS_CONTEXT)

SoluGon: move all dependencies into parameter list.


Copyright 2014 Oracle and/or its aliates. All rights reserved. |

11g_frc_vpd.sql
11g_frc_vpd2.sql

Managing the Result Cache


Oracle oers a number of ways to manage the result cache and tune it to
your specic applicaGon needs.
And that tuning process is cri+cal!

RESULT_CACHE_MAX_SIZE iniGalizaGon parameter


If the cache is too small, then the LRU algorithm negates the point of the cache.

DBMS_RESULT_CACHE management package


v$RESULT_CACHE_* performance views

show_frc_dependencies.sp

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Look for opportuni8es to cache!


Always look for opportuniGes to cache data.
Are there tables that are always staGc during user sessions?
Are there tables that are queried much more frequently than they are changed?

But cache with care!


Caching inappropriately can lead to delivery of dirty data to your users.

The funcGon result cache oers the most declaraGve, widest impact
caching technique available to PL/SQL developers.

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Turbo-charge SQL with Bulk Processing

Improve the performance of repeated SQL operaGons by an order


of magnitude with bulk/array processing in PL/SQL!
CREATE OR REPLACE PROCEDURE upd_for_dept (
dept_in IN employee.department_id%TYPE
,newsal_in IN employee.salary%TYPE)
IS
CURSOR emp_cur IS
SELECT employee_id,salary,hire_date
FROM employee WHERE department_id = dept_in;
BEGIN
FOR rec IN emp_cur LOOP
adjust_compensation (rec, newsal_in);
UPDATE employee SET salary = rec.salary
WHERE employee_id = rec.employee_id;
END LOOP;
END upd_for_dept;

Row by row processing:


elegant but inefficient

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Row by row processing of DML in PL/SQL


Oracle server

SQL Engine

PL/SQL RunGme Engine

PL/SQL block

FOR rec IN emp_cur LOOP


UPDATE employee
SET salary = ...
WHERE employee_id =
rec.employee_id;
END LOOP;

Procedural
statement
executor

SQL
statement
executor

Performance penalty
for many context
switches
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Bulk Processing in PL/SQL


The goal is straighrorward: reduce the number of context switches and
you improve performance.
To do this, Oracle "bundles up" the requests for data (or to change data)
and then passes them with a single context switch.
FORALL speeds up non-query DML.
Use with inserts, updates, deletes and merges.
Move data from collecGons to tables.

BULK COLLECT speeds up queries.


Can be used with all kinds of queries: implicit, explicit, staGc and dynamic.
Move data from tables into collecGons.

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Bulk processing with FORALL


Oracle server

SQL Engine

PL/SQL RunGme Engine

PL/SQL block

FORALL indx IN
list_of_emps.FIRST..
list_of_emps.LAST
UPDATE employee
SET salary = ...
WHERE employee_id =
list_of_emps(indx);
Update...
Update...
Update...
Update...
Update...
Update...

Procedural
statement
executor

Fewer context switches,


same SQL behavior
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

SQL statement
executor

Update...
Update...
Update...
Update...
Update...
Update...

Impact of Bulk Processing in SQL layer

The bulk processing features of PL/SQL change the way the PL/SQL engine
communicates with the SQL layer.
For both FORALL and BULK COLLECT, the processing in the SQL engine is
almost completely unchanged.
Same transacGon and rollback segment management
Same number of individual SQL statements will be executed.

Only one dierence: BEFORE and AFTER statement-level triggers only


re once per FORALL INSERT statements.
Not for each INSERT statement passed to the SQL engine from the FORALL
statement.
statement_trigger_and_forall.sql

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

BULK COLLECT for mul8-row querying


SELECT * BULK COLLECT INTO collection(s) FROM table;
FETCH cur BULK COLLECT INTO collection(s);
EXECUTE IMMEDIATE query BULK COLLECT INTO collection(s);

Retrieve mulGple rows into a collecGon with a single fetch (context switch to the SQL
engine).
Deposit the mulGple rows of data into one or more collec+ons.

NO_DATA_FOUND is not raised when no rows are fetched; instead, the collecGon is
empty.
The "INTO" collecGons are lled sequenGally from index value 1.
There are no "gaps" between 1 and the index value returned by the COUNT method.

Only integer-indexed collecGons may be used.


No need to iniGalize or extend nested tables and varrays. Done automaGcally by
Oracle.
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

BULK COLLECT for Implicit Cursor


Declare a nested table
of records to hold the
queried data.

Fetch all rows into


collection sequentially,
starting with 1.

Iterate through the


collection contents with
a loop.

DECLARE
TYPE employees_aat IS TABLE OF
employees%ROWTYPE;
l_employees employees_aat;
BEGIN
SELECT *
BULK COLLECT INTO l_employees
FROM employees;
FOR indx IN 1 .. l_employees.COUNT
LOOP
process_employee (l_employees(indx));
END LOOP;
END;

bulkcoll.sql
bulkcollect.tst
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Limi8ng retrieval with BULK COLLECT


If you are certain that your table with never have more than N rows, use a
VARRAY (N) to hold the fetched data.
If that limit is exceeded, Oracle will raise an error.
This is not, however, a very common scenario.

If you do not know in advance how many rows you might retrieve, you
should:
1. Declare an explicit cursor.
2. Fetch BULK COLLECT with the LIMIT clause.

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Limit # of rows returned by BULK COLLECT


Use the LIMIT clause with the INTO to
manage the amount of memory used
with the BULK COLLECT operaGon.

Denitely the preferred approach in
producGon applicaGons with large or
varying datasets.

Always check the contents of the
collecGon, as opposed to the
%NOTFOUND aiributes, to determine if
you fetched and processed all rows.

bulklimit.sql

CREATE OR REPLACE PROCEDURE bulk_with_limit


(deptno_in IN dept.deptno%TYPE)
IS
CURSOR emps_in_dept_cur IS
SELECT * FROM emp
WHERE deptno = deptno_in;
TYPE emp_tt IS TABLE OF
emps_in_dept_cur%ROWTYPE;
emps emp_tt;
BEGIN
OPEN emps_in_dept_cur;
LOOP
FETCH emps_in_dept_cur
BULK COLLECT INTO emps LIMIT 1000;
EXIT WHEN emps.COUNT = 0;
process_emps (emps);
END LOOP;
END bulk_with_limit;
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

When to convert to BULK COLLECT


Prior to Oracle10g, you should convert all mulGple row fetch code to BULK
COLLECTs.
On 10.1 and higher, the opGmizer will automaGcally opGmize cursor FOR
loops to run at performance levels similar to BULK COLLECT.
So leave your cursor for loops in place if they...
contain no DML operaGons.
seem to be running fast enough.

Explicit BULK COLLECTs will usually run a li6le faster than cursor for loops
opGmized to BC.
10g_optimize_cfl.sql
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Use the FORALL Bulk Bind Statement


PROCEDURE upd_for_dept (...) IS
BEGIN
FORALL indx IN low_value .. high_value
UPDATE employee
SET salary = newsal_in
WHERE employee_id = list_of_emps (indx);
END;

Instead of execuGng repeGGve, individual DML statements, load up variables


into an array and bind that array into a "template" DML statement.
Only a single DML statement is allowed per FORALL
Can be used with staGc and dynamic SQL

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

bulkGming.sql

Key features and limita8ons of FORALL


Use SQL%BULK_ROWCOUNT to determine the number of rows modied by
each statement executed.
SQL%ROWCOUNT returns total number of rows modied by the enGre FORALL.

Use SAVE_EXCEPTIONS and SQL%BULK_EXCEPTIONS to conGnue past


excepGons in any of the statements.
Granular error recovery and logging
Can also use LOG ERRORS in DML statement in place of SAVE EXCEPTIONS

Use INDICES OF or VALUES OF when bind array is sparse.


bulk_rowcount.sql
bulkexc.sql
10g_indices_of*.sql
10g_values_of*.sql
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

From OldFashioned to Modern Code


TradiGonal PL/SQL code oten involves a cursor FOR loop and mulGple DML
statements inside the loop.
An integrated, row-by-row approach with the opGon of trapping and conGnuing past
excepGons.
Elegant and exible, but slow.

Bulk processing means a switch to "phased approach".


Compared to the funcGon result cache, your code will require much more extensive
reworking.
Code will get more complex and larger in size.
That's the price we pay for changing the way PL/SQL communicates with SQL.

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

A phased approach with bulk processing


Change from integrated, row-by-row approach to a phased approach.
RelaGonal
Table(s)

Phase 1: Bulk collect from table(s) to collecGon

Phase 2: Modify contents of collecGon


according to requirements

RelaGonal
Table
Phase 3: FORALL from collecGon to table
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

c_to_bulk_0.sql
c_to_bulk_5.sql

Bulk Processing Conclusions


Most important performance tuning feature in PL/SQL.
Almost always the fastest way to execute mulG-row SQL operaGons in PL/SQL.

You trade o increased complexity of code for dramaGcally faster


execuGon.
But in Oracle Database 10g and above, the compiler will automaGcally opGmize
cursor FOR loops to BULK COLLECT eciency.
No need to convert unless the loop contains DML.

Watch out for the impact on PGA/UGA memory!

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

The NOCOPY hint


By default, Oracle passes all OUT and IN OUT arguments by value, not
reference.
This means that OUT and IN OUT arguments always involve some copying of data.
All IN arguments are always passed by reference (no copying).

With NOCOPY, you turn o the copy process.


But it comes with a risk: Oracle will not automaGcally "rollback" or reverse changes
made to your variables if the NOCOPY-ed program raises an excepGon.

nocopy*.*
string_nocopy.*
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Op8mizing Func8on Execu8on in SQL


That seems like an awfully good idea!
Two methods:
WITH clause that denes a funcGon
UDF pragma

WITH FUNCTION: dene a funcGon directly within your SQL statement.


Most helpful for avoiding redundancy in long SQL statements

UDF pragma declaraGvely tells the compiler to "prepare" the funcGon for
execuGon from SQL.
Reduces the cost of the context switch
12c_with_funcGon*.sql
12c_udf*.sql
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

High Performance PL/SQL a summary


Make sure you take advantage of the most important opGmizaGon
features:
BULK COLLECT and FORALL
Cached data

PrioriGze maintainability of code over obsessively opGmized code.


Then idenGfy boilenecks and apply the more specialized opGmizaGon
techniques.
NOCOPY is a ne example, though you can usually apply this proacGvely with small
risk.
UDF pragma key point is to analyze how your funcGon would be used

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

Q+A
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

31

Keep Learning with Training from Oracle University


Hands-on training delivered in-class or online by
tenured instructors around the world
New subscripGon-based learning services to give you
any-Gme access to training
CerGcaGon programs to validate your skills

educa8on.oracle.com
Copyright 2014 Oracle and/or its aliates. All rights reserved. |

32

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

33

Copyright 2014 Oracle and/or its aliates. All rights reserved. |

34

35