OTN homepageOTN homepage
TechnologiesTechnologies
PL/SQLPL/SQL
otn.oracle.com/tech/pl_sqlotn.oracle.com/tech/pl_sql
What kind of enhancements?
TransparentSemi-transparentNew features
– New constructs in the language– Richer APIs in the supplied packages
Implementation
Feature Perf Funct UseFeatureFeature PerfPerf FunctFunct UseUse
Native compilation of PL/SQLNative compilation of PL/SQLNative compilation of PL/SQL
Manipulating records faster by up to 5xManipulating records faster by up to 5xManipulating records faster by up to 5x
Inter-package calls faster by up to 1.5xInterInter--package calls faster by up to 1.5xpackage calls faster by up to 1.5x
Utl_Tcp native implementationUtl_TcpUtl_Tcp native implementationnative implementation
Common SQL parserCommon SQL parserCommon SQL parser
Language features
Feature Perf Funct UseFeatureFeature PerfPerf FunctFunct UseUse
Table functionsTable functionsTable functions
Cursor expressionsCursor expressionsCursor expressions
Multilevel collectionsMultilevel collectionsMultilevel collections
Bulk binding in native dynamic SQLBulk binding in native dynamic SQLBulk binding in native dynamic SQL
Exception handling in bulk binding DML operationsException handling in bulkException handling in bulk binding binding DML operationsDML operations
CASE statements and CASE expressionsCASE statements and CASE expressionsCASE statements and CASE expressions
Exception handling in bulk DML
Consider giving employees a 10% raise where employee_id among the values in a table of numbers…forall j in id.first..id.last
There might be a per department salary cap– so some intended updates will failPre-Oracle9i the whole bulk statement failedNow the OK updates will fail and the exceptions can be reportedsave exceptionssql%bulk_exceptions collection
Multilevel collection syntax
for j in my_multi.first..my_multi.lastloopfor k in my_multi(j).first..my_multi(j).lastloopShow ( my_multi(j)(k) );
end loop;end loop;
Collections can be nested to arbitrary depth
CASE statement syntax
case nwhen 1 then Action1;when 2 then Action2;when 3 then Action3;else ActionOther;
end case;
CASE statement syntax
casewhen p = 1 then Action1;when q = 1 then Action2;when r > 1 then Action3;else ActionOther;
end case;
“searched” variety
CASE expression syntax
text := case nwhen 1 then 'one'when 2 then 'two'when 3 then 'three'else 'other'
end;
CASE expression syntax
text := casewhen p = 1 then 'one'when r = 2 then 'two'when q > 1 then 'three'else 'other'
end;
“searched” variety
CASE_NOT_FOUND exceptionbeginp:=0; q:=0; r:=0;casewhen p = 1 then Action1;when r = 2 then Action2;when q > 1 then Action3;
end case;exceptionwhen case_not_found thenShow ('Exception: case_not_found' );
end;
Language features – cont.
Feature Perf Funct UseFeatureFeature PerfPerf FunctFunct UseUse
VARCHAR2 <-> NVARCHAR2 (etc) assignmentVARCHAR2 <VARCHAR2 <--> NVARCHAR2 (etc) assignment> NVARCHAR2 (etc) assignment
VARCHAR2 <-> CLOB assignmentVARCHAR2 <VARCHAR2 <--> CLOB assignment> CLOB assignment
SUBSTR and INSTR w/ CLOBSUBSTR and INSTR w/ CLOBSUBSTR and INSTR w/ CLOB
Seamless access to new SQL features
e.g. MERGE, multitable insert, new time datatypes…
Seamless access to new SQL featuresSeamless access to new SQL features
e.g. MERGE, multitable insert, new time datatypese.g. MERGE, multitable insert, new time datatypes……
OO: Schema evolutioninheritance supporta.k.a. subtyping and polymorphism
OOOO: : Schema evolutionSchema evolutioninheritance supportinheritance supporta.k.a. subtyping and polymorphisma.k.a. subtyping and polymorphism
Supplied packages
Feature Perf Funct UseFeatureFeature PerfPerf FunctFunct UseUse
Utl_Http enhancedUtl_HttpUtl_Http enhancedenhanced
Utl_Raw enhancedUtl_Utl_Raw Raw enhancedenhanced
Utl_File enhancedUtl_FileUtl_File enhancedenhanced
Nineteen new packagesNineteenNineteen new packagesnew packages
Utl_Http enhancementsUsed to send HTTP request and handle the reply mechanically – especially in B2B applicationsOracle9i adds…
– “POST” method – arbitarily long request– Authentication– Access to return status code– RAW reply– cookie support
I.e. provides full support for the semantics that can be expressed via HTTPFull functionality for character set conversion for request and reply
I can’t possiblytalk abouteverythingon that list
in detail!
I can’t possiblytalk abouteverythingon that list
in detail!
So insteadI’m going topick just a coupleto look atin depth…
So insteadI’m going topick just a coupleto look atin depth…
• Native compilation• Native compilation
• Table functionsand cursor expressions
• Table functionsand cursor expressions
Native compilation of PL/SQL
When PL/SQL is used as a thin wrapper for SQL its execution speed is rarely an issueBut we see an increasing trend to use PL/SQL for computationally intensive database independent tasksHere it is the execution speed of the PL/SQL code that determines the performance
Background
Pre-Oracle9i, compilation of PL/SQL source code always results in bytecode which is stored in the database and interpreted at run-time by a virtual machine implemented within ORACLE
What’s new?
In Oracle9i PL/SQL source code may optionally be compiled into native object code which is linked into ORACLE
What’s the benefit?
Speed increased by up to 40%“Thin wrapper” programs won’t speed up so much
…but they won’t slow down!
How does it work?
The code generator translates the PL/SQL source code into C source codeThis is compiled on the given platform and stored as object files on the filesystem……and then linked into ORACLE
How do you do it?
One-time DBA setupThe developer chooses at compile time via the session parameter…
plsql_compiler_flags
One-time DBA setup
Specify 3rd party utilities for compiling and linking– Should be owned by the ORACLE owner– Only the ORACLE owner should have
write accessSpecify directories for the compiled object librariesDone via system parameters
Developer choice
alter sessionset plsql_compiler_flags =
'NATIVE'/* or 'INTERPRETED' */;
sets the compilation mode for subsequently compiled PL/SQL library units
Oracle recommends…
All PL/SQL library units that are called from a given natively compiled top-level unit should also be compiled natively
there is a cost for the context switch when a library unit compiled in native mode invokes one compiled in interpreted mode
Recommendation includes the Oracle-supplied library units (by default these are compiled in interpreted mode)
Oracle9i in Action
170 Systems, Inc have been an Oracle Partner for eleven years and participated in the Beta Program for the Oracle9i Database with particular interest in PL/SQL Native CompilationThey have now certified their 170 MarkView Document Management and Imaging System™against Oracle9iThey have updated the install scripts to optionally turn on Native Compilation
170 MarkViewDocument Managementand Imaging System
Provides Content Management, Document Management, Imaging and Workflow solutionsTightly integrated with the Oracle9i Database, Oracle9i Application Server andthe Oracle E-Business SuiteEnables businesses to capture and manage all of their information online in a single, unified system
170 MarkView™
Customers include…– British Telecommunications– E*TRADE Group– the Apollo Group– the University of Pennsylvania
Very large numbers of documents, images, concurrent users, and high transaction ratesPerformance and scalability especially important
Large-scale multi-user, multi-access system
170 MarkView™
Business logic, including preparation of data for presentation, is implemented in the database in PL/SQL
Involves complex logic and intensive string processing supported by stacks and lists of values modeled as PL/SQL collections.
Visit 170 Systems at Booth # 1914
170 Systems
Have observed a performance increase of up to 40% for computationally intensive routines
…and no performance degradation
Native Compilation - summary
It’s a semi-transparent enhancementIt gives you improved performanceTry it !
Table functionsand cursor expressions
Cursor variables – recapManipulating cursor expressions in PL/SQLUsing a cursor expressionas an actual parameter to a PL/SQL functionTable functions pre-Oracle9iOracle9i pipelined table functionsDaisy-chaining table functionsParallelization
Cursor variables - recap
Supported pre-Oracle9iAllow encapsulation of logicspecific to tuples of a particular formatto be independent ofthe concrete SELECT statementwhich retrieves them
Cursor variables - recap
procedure Bulk_Fetch_From_Cursor( p_cursor in sys_refcursor )
is...
SYS_REFCURSOR is a new Oracle9iusability featureDefines a generic weak cursor once and for all
Set up the target
Declare an index-by PL/SQL table for thefetched rows
...istype names_t istable of varchar2(4000)index by binary_integer;
the_names names_t;begin...
Do the bulk fetch
fetch p_cursorbulk collectinto the_names;
Works pre-Oracle9iPerformance boost because reduces context switching between PL/SQL and SQL engines
Process the results
for j in the_names.first..the_names.lastloopShow ( the_names(j) );
end loop;
Works pre-Oracle9i
Invoke the proceduredeclarethe_cursor sys_refcursor;
beginopen the_cursor for'select last_name from employees
order by last_name';Bulk_Fetch_From_Cursor ( the_cursor );close the_cursor;
Note we’re using Native Dynamic SQL
New in Oracle9i
This is just one example of bulk binding working with native dynamic SQLThe combination now works in all situations
– DefiningSELECT
– In-bindingFORALL … USING
– Out-bindingFORALL … USING … RETURNING
Table functionsand cursor expressions
Cursor variables – recapManipulating cursor expressions in PL/SQLUsing a cursor expressionas an actual parameter to a PL/SQL functionTable functions pre-Oracle9iOracle9i pipelined table functionsDaisy-chaining table functionsParallelization
Cursor expressions and PL/SQL
Suppose we want to make a pretty print
…listing departments
…and under each department list its employees
Explicit 3GL approach
for department in ( select ... )loopShow ( department.department_name );for employee in ( select ...where department_id =
department.department_id )loopShow ( employee.last_name );
This SQL does the job in one go
selectdepartment_name,cursor (
select last_namefrom employees ewhere e.department_id =
d.department_id)
from departments d;
Use in it PL/SQL – new in Oracle9i
declarecursor depts isselect
department_name,cursor ( select ... )
from departments d;
Since there’s only one SQL statement(we had two in the explicit approach)the CBO has a better chance
Set up the fetch targets
Just for fun we’ll do some bulk fetching
v_dname dep...%type;emps sys_refcursor;
type enames_t is table of emp...%typeindex by...;
v_enames enames_t;
Outer loop
Fetch the cursor into the ref cursor targetand then fetch it (bulk) into its targetopen depts;loopfetch depts into v_dname, emps;exit when depts%notfound;Show ( v_dname );fetch empsbulk collect into v_ename;
Inner loop
Process the bulk fetched results
for j in v_ename.first..v_ename.lastloopShow ( v_ename(j) );
end loop;
Table functionsand cursor expressions
Cursor variables – recapManipulating cursor expressions in PL/SQLUsing a cursor expressionas an actual parameter to a PL/SQL functionTable functions pre-Oracle9iOracle9i pipelined table functionsDaisy-chaining table functionsParallelization
Cursor terminology
A cursor variable (i.e. a variable of typeREF CURSOR) points to an actual cursorIt may be used as a formal parameter to a PL/SQL procedure or functionA cursor expression defines an actual cursor…and is legal in a SQL statement
Func ( cursor ( select c from t ) )
So you’d expect to write…
Cursor expression as an actual parameter to a PL/SQL function
Pre-Oracle9i this was never allowedAt Oracle9i it is allowed…
…when a function is invoked ina top level SQL statement
Cursor expression inWHERE clause functionselect ...from employees managers where Func(cursor ( < select stuff for
this manager's reports > ),managers.hire_date
) = 1;
Cursor expression inWHERE clause function
We’re deciding on the basis of elaborate procedural logicWriting the whole thing as a procedure you need to output to a tableWith the logic in a WHERE clause function you can define a VIEW for dynamic reuse
A cursor expressioncan be an actual parameterto a PL/SQL functionin a top levelSQL statement
A cursor expressioncan be an actual parameterto a PL/SQL functionin a top levelSQL statement
Hold that thought…
Table functionsand cursor expressions
Cursor variables – recapManipulating cursor expressions in PL/SQLUsing a cursor expressionas an actual parameter to a PL/SQL functionTable functions pre-Oracle9iOracle9i pipelined table functionsDaisy-chaining table functionsParallelization
Pre-Oracle9i table function
We define our row, and a table of our rows…
create type my_rowas object ( idx number,
text varchar2(20) );
create type my_tab as table of my_row;
Pre-Oracle9i table function
function Func return my_tab isv_tab my_tab;
beginv_tab := my_tab ( my_row ( ... ) );< extend the table and compute the rows >return v_tab;
end Func;
All the rows are created before the function returns
Pre-Oracle9i table function
select *from table( cast
( Func() as my_tab ));
Nice, but the response characterstics are not what we’re used to with a rowsource
Table functionsand cursor expressions
Cursor variables – recapManipulating cursor expressions in PL/SQLUsing a cursor expressionas an actual parameter to a PL/SQL functionTable functions pre-Oracle9iOracle9i pipelined table functionsDaisy-chaining table functionsParallelization
Oracle9i pipelined table function
function Func return my_tab pipelined isv_row my_row;
beginfor ...loopv_row := my_row ( ... );pipe row ( v_row );
end loop;return;
end Func;
As soon asa row is computed,it’s deliveredrowsource-style
As soon asa row is computed,it’s deliveredrowsource-style
Hold that thought too…
Note:
The pipelined and pipe row keywordscan only be used together as shownA pipelined table function can be invokedonly in the FROM list of a SELECT clause
select * from table ( Func() );
We can now use a simpler syntax…
We can now use package-level types for the row and for the table
Table functionsand cursor expressions
Cursor variables – recapManipulating cursor expressions in PL/SQLUsing a cursor expressionas an actual parameter to a PL/SQL functionTable functions pre-Oracle9iOracle9i pipelined table functionsDaisy-chaining table functionsParallelization
Remember…
A cursor expression can be an actual parameter to a PL/SQL function in a top level SQL statementSo a table function may now be defined with an input parameter of type REF CURSOR and invoked with a cursor expression as the actual parameter
function Func_2 ( p_cur in sys_refcursor )return Pkg.my_tab pipelined isv_in_row Pkg.my_in_row;v_out_row Pkg.my_row;
beginloopfetch p_cur into v_in_row;exit when p_cur%notfound;
< compute out-row(s) from in-row(s) >pipe row ( v_out_row );
end loop;close p_cur;return;
end Func_2;
We’re consuming in-rows,Transforming them procedurally to out-rowswith an arbitrarily complex M:N algorithm,and piping out-rowsas soon as they’re ready
We’re consuming in-rows,Transforming them procedurally to out-rowswith an arbitrarily complex M:N algorithm,and piping out-rowsas soon as they’re ready
How do we use it?
Suppose t is a table which supports a select list compatible with Pkg.my_rowWe can now invoke the table function thus…
select * from table(Func_2( cursor ( select * from t ) )
);
Think about it…
We now have a very powerful generic transformation techniqueIt starts with the results from a SELECT and transforms them into something you can SELECTfromSounds familiar?Note: don’t forget, the table function can have ordinary input parameters
Think of a table functionas a deluxe,parameterizable view
Think of a table functionas a deluxe,parameterizable view
t might have been a view…create view t asselect * from table ( Func() );
So we’d actually be doing…
select * from table(Func_2 ( cursor(select * from table ( Func() ) )
));
Daisy-chaining
We can plug any number of transformationsback-to-backEach can perform an arbitrarily complex transformationThe starting point could be an Oracle tableOr it could be a table functionthat accesses external datavia Utl_Fileor via the call-out framework
Table functionsand cursor expressions
Cursor variables – recapManipulating cursor expressions in PL/SQLUsing a cursor expressionas an actual parameter to a PL/SQL functionTable functions pre-Oracle9iOracle9i pipelined table functionsDaisy-chaining table functionsParallelization
Who’s going to use them?
The driver for developing table functions was datawarehousing, especially the ETL phaseSo of course the story wouldn’t be complete without a parallel capabilityLet’s look at the syntax…
PARALLEL_ENABLE syntax
function Func_2 ( p_cur in sys_refcursor )return Pkg.my_tabpipelinedparallel_enable ( partition p_cur by any )
is...
Must have an input REF CURSOR parameter to drive the partitioningANY is the simple, special case – results don’t depend on the order of processing
Caution…
If you use ANY and your assertion is wrong, the results will be unpredictableThe developer must design the algorithm so that the results don’t depend on the degree of parallelism
What if the results do dependon the order of processing?
We can be more explicit when we declare how we want the input rows to be partitionedThis requires that we have a strongly typed input cursor, e.g…
package Pkg istype my_row is record ( n number, ... );type cur_t is ref cursor return my_row;
end Pkg;
CLUSTER … BYfunction Func_3 ( p_cur in Pkg.cur_t )return Pkg.my_tabpipelinedparallel_enable( partition p_cur by hash (n) )
cluster p_cur by (n)is...
The algorithm requires that all rows for a given value of n come together to a single slave……but doesn’t care about the order
ORDER … BYfunction Func_4 ( p_cur in Pkg.cur_t )return Pkg.my_tabpipelinedparallel_enable( partition p_cur by range (n) )
order p_cur by ( n, m )is...
Not only must all rows for a given value of n come together to a single slave……but also they must be ordered by n, m
Using Oracle9i table functions…
t3t3t2t2t1t1
t3t3t2t2t1t1
t3t3t2t2t1t1
t3t3t2t2t1t1
t3t3t2t2t1t1
datadatawarehouse
oltpoltpwarehouse
pipelined parallelized
Comparison…
Sun Ultra-Enterprise 45003 GB RAM, 10 CPUs of 168 MHz1,000,000 row source table1 row in to 7 rows out pivot transformOracle8i – PL/SQL cursor loop with 7 INSERTsOracle9i – table function with 7 PIPE ROWsPerformance and Scalability in DSS Environmentwith Oracle9i,Neil Thombre, Oracle Corp – OOW paper #822also on otn.oracle.com/deploy/performance/
87 87 minmin
Oracle8Oracle8iiOracle9Oracle9iipipelinedpipelined
37 37 minmin
2.4 2.4 xx
Oracle9Oracle9iipipelinedpipelinedparallel 20parallel 20
12 12 minmin
7.5 7.5 xx
Table Functions - summary
An exciting new language feature
Generic applicability…think deluxe, parameterizable view
Especially beneficial inExtraction Load Transformationphase in warehousing applications
Oracle9i PL/SQL gives you…
Improved performanceIncreased functionalityBetter usability for the developer
you should upgrade !you should upgrade !