+ All Categories
Home > Technology > AMIS - Can collections speed up your PL/SQL?

AMIS - Can collections speed up your PL/SQL?

Date post: 18-May-2015
Category:
Upload: amis-friends-of-oracle-and-java
View: 595 times
Download: 0 times
Share this document with a friend
Description:
Deze presentatie is gegeven tijdens de KScope conferentie 2012Spreker: Patrick BarelTitel Can Collections Speed Up Your PL/SQL?Onderwerp: Developers Toolbox - Coding Deze presentatie gaat over het gebruik van Collections in PL/SQL. Hoe werken deze arrays? Hoe gebruikt Oracle deze structuren in één van de belangrijkste verbeteringen op het gebied van prestaties van PL/SQL code in combinatie met uitgevoerde SQL queries? Daarnaast wordt er ingegaan op het gebruik van Table Functions, waarmee je kracht van PL/SQL in SQL kunt gebruiken. In deze sessie leer je om met minimale inspanning een grote verbetering in de performance en onderhoudbaarheid van je PL/SQL code te bereiken.
Popular Tags:
58
Patrick Barel , AMIS, The Netherlands Wednesday, June 27, 2012 ODTUG KScope 12 San Antonio, Texas, USA Developers Toolbox - Coding Can collections speed up your PL/SQL?
Transcript
Page 1: AMIS - Can collections speed up your PL/SQL?

Patrick Barel , AMIS, The Netherlands

Wednesday, June 27, 2012

ODTUG KScope 12

San Antonio, Texas, USA

Developers Toolbox - Coding Can collections speed up your PL/SQL?

Page 2: AMIS - Can collections speed up your PL/SQL?

Agenda

Records

Collections

Bulk Processing

Table Functions

Page 3: AMIS - Can collections speed up your PL/SQL?

Record

Page 4: AMIS - Can collections speed up your PL/SQL?

Records

Table

View

Cursor

User Defined

} %rowtype

Page 5: AMIS - Can collections speed up your PL/SQL?

Records

Record type definition

Field definition

TYPE record_type IS RECORD field_definition (

,

) ;

field datatype

NOT NULL :=

DEFAULT

expression

Page 6: AMIS - Can collections speed up your PL/SQL?

Collections

Three types available

PL/SQL Tables

Index by Tables

Associative Arrays

Page 7: AMIS - Can collections speed up your PL/SQL?

Collections

Three types available

Associative Arrays

Nested Tables

Varrays

Page 8: AMIS - Can collections speed up your PL/SQL?

Collections

Three types available

Associative Arrays

Nested Tables

Varrays

PL/SQL Only

SQL and PL/SQL

SQL and PL/SQL

Page 9: AMIS - Can collections speed up your PL/SQL?

PL/SQL Collections (3 Types)

Associative Arrays

Varrays

Nested Tables

Page 10: AMIS - Can collections speed up your PL/SQL?

Number of elements is unbounded, practically speaking.

Valid row numbers range from -231+1 to 231-1. (i.e. -2,147,483,647 to 2,147,483,647)

This range allows you to employ the row number as an intelligent key, such as the primary key or unique index value, because…

AAs also:

Can be sparse.

Data does not have to be stored in consecutive rows, as is required in traditional 3GL arrays and VARRAYs.

Can have index values of integers or strings (Oracle9i R2 and above).

assoc_array_example.sql

collection_of_records.sql

count_vs_rowcount.sql

About Associative Arrays

Page 11: AMIS - Can collections speed up your PL/SQL?

Name Changes:

7: PL/SQL Tables

8i: Index By Tables

9i: Associative Arrays

Single dimensioned, unbounded, sparse collection of

homogeneous elements

PL/SQL Only value key

Associative Arrays

Page 12: AMIS - Can collections speed up your PL/SQL?

First

Last

Next (n)

Prior (n)

Count

Exists (n)

Delete [(n[,m])]

idx := emp_t.first;

idx := emp_t.last;

idx := emp_t.next (idx);

idx := emp_t.prior (idx);

idx := emp_t.count;

if emp_t.exists (idx)

then

...

end if;

emp_t.delete (1);

emp_t.delete (2, 4);

emp_t.delete;

Methods

Page 13: AMIS - Can collections speed up your PL/SQL?

declare

type num_tbl is table of number

index by binary_integer;

l_num_tbl num_tbl;

l_idx integer;

begin

...

value key

Associative Array

Page 14: AMIS - Can collections speed up your PL/SQL?

declare

type num_tbl is table of number

index by binary_integer;

l_num_tbl num_tbl;

l_idx integer;

begin

l_num_tbl(1):= 12;

l_num_tbl(54):= 5;

...

value

12

5

key

1

54

Associative Array

Page 15: AMIS - Can collections speed up your PL/SQL?

declare

type num_tbl is table of number

index by binary_integer;

l_num_tbl num_tbl;

l_idx integer;

begin

l_num_tbl(1):= 12;

l_num_tbl(54):= 5;

l_num_tbl(3):= 98;

l_num_tbl(5):= l_num_tbl.count;

l_idx:= l_num_tbl.first;

...

end;

value

12

98

3

key

1

3

5

5 54

Associative Array

Page 16: AMIS - Can collections speed up your PL/SQL?

value

12

5

key

1

54

2

10

declare

type num_tbl is table of number

index by binary_integer;

l_num_tbl num_tbl;

l_idx integer;

begin

l_num_tbl(1):= 12;

l_num_tbl(54):= 5;

l_num_tbl(3):= 98;

l_num_tbl(5):= l_num_tbl.count;

l_idx:= l_num_tbl.first;

loop

dbms_output.put_line(l_num_tbl(l_idx));

l_idx:= l_num_tbl.next(l_idx);

exit when l_idx is null;

end loop;

l_num_tbl.delete(2,10);

dbms_output.put_line(l_num_tbl.count);

end;

value

12

98

3

key

1

3

5

5 54

Associative Array

Page 17: AMIS - Can collections speed up your PL/SQL?

declare

type str_tbl is table of varchar2(40)

index by varchar2(40);

l_str_tbl str_tbl;

l_idx varchar2(40);

begin

...

value key

Associative Array VARCHAR2 Key

Page 18: AMIS - Can collections speed up your PL/SQL?

declare

type str_tbl is table of varchar2(40)

index by varchar2(40);

l_str_tbl str_tbl;

l_idx varchar2(40);

begin

l_str_tbl('one'):= 'een';

l_str_tbl('two'):= 'twee';

...

value

een

twee

key

one

two

Associative Array VARCHAR2 Key

Page 19: AMIS - Can collections speed up your PL/SQL?

declare

type str_tbl is table of varchar2(40)

index by varchar2(40);

l_str_tbl str_tbl;

l_idx varchar2(40);

begin

l_str_tbl('one'):= 'een';

l_str_tbl('two'):= 'twee';

l_str_tbl('three'):= 'drie';

l_str_tbl('four'):= 'vier';

l_idx:= l_str_tbl.first;

...

end;

value

vier

een

drie

key

four

one

three

twee two

Associative Array VARCHAR2 Key

Page 20: AMIS - Can collections speed up your PL/SQL?

declare

type str_tbl is table of varchar2(40)

index by varchar2(40);

l_str_tbl str_tbl;

l_idx varchar2(40);

begin

l_str_tbl('one'):= ‘een';

l_str_tbl('two'):= ‘twee';

l_str_tbl('three'):= 'drie';

l_str_tbl('four'):= 'vier';

l_idx:= l_str_tbl.first;

loop

dbms_output.put_line(l_str_tbl(l_idx));

l_idx:= l_str_tbl.next(l_idx);

exit when l_idx is null;

end loop;

l_str_tbl.delete('o', 'tr');

dbms_output.put_line(l_str_tbl.count);

end;

o

tr

value

vier

een

drie

key

four

one

three

twee two

value

vier

twee

key

four

two

Associative Array VARCHAR2 Key

Page 21: AMIS - Can collections speed up your PL/SQL?

for idx in emp_t.first .. emp_t.last

loop

...

end loop;

for idx in 1 .. emp_t.count

loop

...

end loop;

idx := emp_t.first;

while idx is not null

loop

...

idx := emp_t.next (idx);

end loop;

• Dense

• Count > 0

• Dense

• …

Retrieval

Page 22: AMIS - Can collections speed up your PL/SQL?

PL/SQL Collections (3 Types)

Associative Arrays

Varrays

Nested Tables

Page 23: AMIS - Can collections speed up your PL/SQL?

varray_example.sql

About Varrays

Has a maximum size, associated with its type.

Can adjust the size in Oracle10g R2.

Part of object model, requiring initialization.

Is always dense; you can only remove elements

from the end of a varray.

Can be defined as a schema level type and used

as a relational table column type.

Page 24: AMIS - Can collections speed up your PL/SQL?

Single dimensioned, always bounded, never

sparse collection of homogeneous elements

SQL and PL/SQL

Can be used as column datatype in a table

Stored “in-line” in same table

Retains its ordering

Needs to be initialized and extended

value key

Varray

Page 25: AMIS - Can collections speed up your PL/SQL?

First

Last

Next (n)

Prior (n)

Count

Exists (n)

Delete

Limit

Extend [(n[,m])]

Trim [(n)]

idx := ename_t.limit;

ename_t.extend (1);

ename_t.trim (1);

ename_t.trim;

Methods

Page 26: AMIS - Can collections speed up your PL/SQL?

declare

type ename_vt is varray (10) of varchar2(10);

ename_t ename_vt;

begin

ename_t := ename_vt();

ename_t.extend (1);

ename_t(1) := 'Spencer';

...

end;

Initialization

declare

type ename_vt is varray (10) of varchar2(10);

ename_t ename_vt := ename_vt ('Davis');

begin

...

end; Initialization and

Extending

Using Varray

Page 27: AMIS - Can collections speed up your PL/SQL?

Pre 10gR2: VARRAY needed to be recreated.

10gr2 and up: ALTER TYPE MODIFY LIMIT

Only to increase the limit

varraylimit.sql

How Variable is the Varray?

Page 28: AMIS - Can collections speed up your PL/SQL?

PL/SQL Collections (3 Types)

Associative Arrays

Varrays

Nested Tables

Page 29: AMIS - Can collections speed up your PL/SQL?

Name reflects fact that this collection can be

"nested" inside relational table as a column.

Type can be defined at schema level.

No practical, pre-defined limit on a nested table.

Valid row numbers range from 1 to 231-1. (i.e. 1 to 2,147,483,647)

Part of object model, requiring initialization.

Is always dense initially, but can become sparse

after deletes.

nested_table_example.sql

About Nested Tables

Page 30: AMIS - Can collections speed up your PL/SQL?

Single dimensioned, unbounded, sparse collection

of homogeneous elements

SQL and PL/SQL

Can be used as column datatype in a table

Stored “out-of-line” in a separate table

Initially dense, can be sparse

value key

Nested Tables

Page 31: AMIS - Can collections speed up your PL/SQL?

First

Last

Next (n)

Prior (n)

Count

Exists (n)

Delete [(n[,m])]

Extend [(n[,m])]

Trim

(Limit)

Methods

Page 32: AMIS - Can collections speed up your PL/SQL?

declare

type ename_nt is table of varchar2(10);

ename_t ename_nt;

begin

ename_t := ename_nt();

ename_t.extend (1);

ename_t(1) := 'Spencer';

...

end;

Initialization

declare

type ename_nt is table of varchar2(10);

ename_t ename_nt := ename_nt ('Davis');

begin

...

end; Initialization and

Extending

Using Nested Tables

Page 33: AMIS - Can collections speed up your PL/SQL?

Differences

Feature Associative Array Nested Table VArray

SQL – PL/SQL PL/SQL only SQL and PL/SQL SQL and PL/SQL

Dense - Sparse Sparse Initially Dense

Can become sparse

Dense

Size ‘Unlimited’ ‘Unlimited’ Limited

Order Unordered Unordered Ordered

Usage Any set of data Any set of data Small sets of data

Use in Table No Yes Yes

Page 34: AMIS - Can collections speed up your PL/SQL?

FORALL Use with inserts, updates and deletes. Move data from collections to tables.

BULK COLLECT Use with implicit and explicit queries. Move data from tables into collections.

In both cases, the "back back" end processing in the SQL engine is unchanged. Same transaction and rollback segment management Same number of individual SQL statements will be

executed. But BEFORE and AFTER statement-level triggers only

fire once per FORALL INSERT statements.

statement_trigger_and_forall.sql

Bulk Processing in PL/SQL

Page 35: AMIS - Can collections speed up your PL/SQL?

Fetch one or more rows into a collection.

Collection is always filled sequentially from index value 1.

Query does not raise NO_DATA_FOUND if no rows are

fetched.

Instead, the collection is empty.

Use FETCH with LIMIT to manage memory.

SELECT * BULK COLLECT INTO collection FROM table;

FETCH cur BULK COLLECT INTO collection;

BULK COLLECT for multi-row querying

Page 36: AMIS - Can collections speed up your PL/SQL?

Fetch one or more rows into a collection.

Collection is always filled sequentially from index value 1.

Query does not raise NO_DATA_FOUND if no rows are

fetched.

Instead, the collection is empty.

Use FETCH with LIMIT to manage memory.

SELECT * BULK COLLECT INTO collection FROM table;

FETCH cur BULK COLLECT INTO collection;

BULK COLLECT for multi-row querying

Page 37: AMIS - Can collections speed up your PL/SQL?

If you are certain that your table will 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.

If you do not know in advance how many rows

you might retrieve, you should:

Declare an explicit cursor.

Fetch BULK COLLECT with the LIMIT clause.

Limiting retrieval with BULK COLLECT

Page 38: AMIS - Can collections speed up your PL/SQL?

The limit value can be a literal or a variable.

Use a variable for the limit to give you

maximum flexibility.

With very large volumes of data and small

numbers of batch processes, however, a larger

LIMIT could help.

Details on that LIMIT clause

Page 39: AMIS - Can collections speed up your PL/SQL?

You will need to break the habit of checking

%NOTFOUND right after the fetch.

You might skip processing some of your data.

Instead, do one of the following:

At the end of the loop, check %NOTFOUND.

Right after fetch, exit when collection.COUNT = 0.

At end of loop, exit when collection.COUNT < limit.

LOOP

FETCH my_cursor BULK COLLECT INTO l_collection LIMIT 100;

EXIT WHEN my_cursor%NOTFOUND; BAD IDEA

bulklimit_stop.sql

Terminating loops containing BULK COLLECT

Page 40: AMIS - Can collections speed up your PL/SQL?

Prior to Oracle10g, you should convert all multiple row

fetch logic, including cursor for loops, to BULK

COLLECTs.

For Oracle10g and above, leave your cursor for loops in

place if they...

contain no DML operations.

seem to be running fast enough.

Explicit BULK COLLECTs will usually run faster than

cursor for loops optimized to Bulk Collect.

When to convert to BULK COLLECT

Page 41: AMIS - Can collections speed up your PL/SQL?

Convert loops that contain inserts, updates or deletes to FORALL statements.

Header looks identical to a numeric FOR loop. Implicitly declared integer iterator At least one "bind array" that uses this iterator as its

index value.

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; Binding array

Use FORALL for multi-row DML operations

Page 42: AMIS - Can collections speed up your PL/SQL?

Use any type of collection with FORALL. One DML statement is allowed per FORALL. Each FORALL is its own "extended" DML statement.

The collection must be indexed by integer. The binding array must be sequentially filled. Unless you use the INDICES OF or VALUES OF clause.

SQL%ROWCOUNT returns total number of rows modified by entire FORALL. Unreliable when used with LOG ERRORS.

Use the SQL%BULK_ROWCOUNT cursor attribute to determine how many rows are modified by each statement.

bulktiming.sql

bulk_rowcount.sql

More on FORALL

Page 44: AMIS - Can collections speed up your PL/SQL?

Prior to Oracle10g R2, the binding arrays in a FORALL

statement must be sequentially filled.

Now, however, you can bind sparse collections by using

INDICES OF and VALUES OF in the FORALL header.

10g_indices_of*.sql

10g_values_of*.sql

PROCEDURE upd_for_dept (...) IS

BEGIN

FORALL indx IN INDICES OF list_of_emps

UPDATE employee

SET salary = newsal_in

WHERE employee_id = list_of_emps (indx);

INDICES OF and VALUES OF

Page 45: AMIS - Can collections speed up your PL/SQL?

When an exception occurs in a DML statement....

That statement is rolled back and the FORALL stops.

All (previous) successful statements are not rolled

back.

Use the SAVE EXCEPTIONS clause to tell Oracle to

continue past exceptions, and save the error information

for later.

Then check the contents of the pseudo-collection of

records, SQL%BULK_EXCEPTIONS.

Two fields: ERROR_INDEX and ERROR_CODE

Exception handling and FORALL

Page 46: AMIS - Can collections speed up your PL/SQL?

slow-by-slow

Change from integrated, row-by-row approach to

a phased approach.

Phase 1: get the data with BULK COLLECT.

Filling those collections

Phase 2: massage collections so they are ready

for DML operations.

Phase 3: push the data to the database with

FORALL.

cfl_to_bulk_0.sql

cfl_to_bulk_5.sql

10g_indices_of.sql

10g_values_of.sql

Converting old-fashioned code to bulk

Page 47: AMIS - Can collections speed up your PL/SQL?

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

SQL operations in PL/SQL. You trade off increased complexity of code for

dramatically faster execution. But in Oracle Database 10g and above, the compiler

will automatically optimize cursor FOR loops to BULK COLLECT efficiency.

No need to convert unless the loop contains DML or you want to maximally optimize your code.

Watch out for the impact on PGA memory!

Bulk Processing Conclusions

Page 48: AMIS - Can collections speed up your PL/SQL?
Page 49: AMIS - Can collections speed up your PL/SQL?

Oracle server

PL/SQL Runtime Engine SQL Engine

PL/SQL block Procedural

statement

executor SQL

statement

executor

OPEN cur; FETCH cur INTO rec; WHILE cur%found LOOP <<Do Stuff>> FETCH cur INTO rec; END LOOP; CLOSE cur;

Performance penalty

for many “context

switches”

Row by row processing of data in PL/SQL

© Steven Feuerstein/Patrick Barel

Page 50: AMIS - Can collections speed up your PL/SQL?

Oracle server

PL/SQL Runtime Engine SQL Engine

PL/SQL block Procedural

statement

executor SQL

statement

executor

OPEN cur; FETCH cur BULK COLLECT INTO col; FOR indx IN col.first .. col.last LOOP <<Do Stuff>> END LOOP; CLOSE cur;

Fewer context switches,

same SQL behavior

Row

Row

Row

Row

Row

Row

Row

Row

Row

Row

Row

Row

Bulk processing with BULK COLLECT

© Steven Feuerstein/Patrick Barel

Page 51: AMIS - Can collections speed up your PL/SQL?

Oracle server

PL/SQL Runtime Engine SQL Engine

PL/SQL block Procedural

statement

executor SQL

statement

executor

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

Performance penalty

for many “context

switches”

Row by row processing of DML in PL/SQL

© Steven Feuerstein

Page 52: AMIS - Can collections speed up your PL/SQL?

Oracle server

PL/SQL Runtime Engine SQL Engine

PL/SQL block Procedural

statement

executor SQL

statement

executor

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

Fewer context switches,

same SQL behavior

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Update...

Bulk processing with FORALL

© Steven Feuerstein

Page 53: AMIS - Can collections speed up your PL/SQL?

Table Functions

Table functions are functions that produce

a collection of rows (either a nested table or a varray)

that can be queried like a physical database table.

You use a table function like the name of a

database table, in the FROM clause of a query.

Page 54: AMIS - Can collections speed up your PL/SQL?

Table Functions

Table functions are based on collections

Must be available in the SQL layer

Nested tables and Varray

Page 55: AMIS - Can collections speed up your PL/SQL?

Table Functions

Create a function in PL/SQL

Make sure it returns a collection

Query it using the TABLE() operator

Table functions can be pipelined (return results as they are produced)

Table functions can be paralellized

Page 56: AMIS - Can collections speed up your PL/SQL?

Table Functions

You can use Table Functions when

Calculations cannot (easily) be done in SQL

You want to take advantage of PL/SQL e.g.

caching or package variables

You want to leverage the power of PL/SQL in

SQL

Make your views more dynamic

Page 57: AMIS - Can collections speed up your PL/SQL?

Online

tahiti.oracle.com

For all documentation online

www.allthingsoracle.com o http://allthingsoracle.com/collections-in-oracle-pt-1/

o http://allthingsoracle.com/collections-in-oracle-part-2/

o http://allthingsoracle.com/bulk-processing-in-oracle-part-1/

o http://allthingsoracle.com/bulk-processing-in-oracle-part-2/

Books

Oracle PL/SQL Programming

Chapter 12 (collections) and

chapter 21 (bulk processing)

Oracle PL/SQL for DBAs

Chapter 1 (collections and bulk processing)

Resources

Page 58: AMIS - Can collections speed up your PL/SQL?

Recommended