Eff PLSQL
Eff PLSQL
Thomas Kyte
http://asktom.oracle.com/
Agenda
• Why PL/SQL?
• Write as little as you can
• Use Packages
• Use Static SQL
• Bulk processing
• Implicit or Explicit?
• Beware of some features
• Things to definitely do
Why PL/SQL
Why Use PL/SQL
• It is a ‘real’ language
– It is not a scripting language
– It is not a ‘toy’, it is used to code ‘real’ things
• Bind Variables
– If you use static SQL in PL/SQL it is impossible to not use bind
variables correctly.
– You have to use cumbersome dynamic SQL to do it wrong.
• Parse Once, Execute many
– PL/SQL does statement caching
– You have to either configure and enable its use in other languages
or
– Do it your self (refer back to java code)
• Schema Changes are safer
– Alter table t modify c1 varchar2(255);
– We can find all uses of T (I didn’t know you were using that, sorry..)
– We can make the change without having to change code
However
• This was a data warehouse load (load 2-3-4 times the data you want,
then delete? Ouch)
• It was wrong – procedural code is no easier to understand than set based
code, documentation is key
More Code = More Bugs
Less Code = Less Bugs
/* Load table t using history tables. History tables have
multiple records per employee. We need to keep the
history records for each employee that have the maximum
status date for that employee. We do that by computing
the max(status_date) for each employee (partition by EMPNO
finding max(status_date) and keeping only the records such
that the status_date for that record = max(status_date)
for all records with same empno */
• With native dynamic SQL, you need to make sure you use the
same SQL text over and over to cache statements
– And if you are doing that, why did you use dynamic SQL again?
– Different in 9i and before than 10g and later
• You get some data (more than a row), process it, and
send it all back (to update/insert/delete).
Bulk Processing
• Either
– Simple, formal OUT parameters
– Ref cursor for all result sets
• Implicit
– With this type of cursor, PL/SQL does most of the work for
you. You don’t have to open close, declare, or fetch from an
implicit cursor. For x in ( select * from t where … )
Loop
…
• Explicit End loop;
– With this type of cursor, you do all of the work. You must
open, close, fetch, and control an explicit cursor completely.
Declare
cursor c is select * from t where …;
l_rec c%rowtype;
Open c;
Loop
fetch c into l_rec;
exit when c%notfound;
…
End loop;
Close c;
Implicit versus Explicit
• Explicit Declare
cursor c is select … from … where …;
Begin
open c;
fetch c into <plsql variables>;
if (c%notfound) then
• These two bits of raise no_data_found;
end if;
code do the same fetch c into <plsql variables>;
if (c%found) then
thing. Which is raise too_many_rows;
end if;
more efficient? close c;
Single Row Processing
----------------------------------------
• This is a ‘worse’ bug
• This I see even more Begin
open c1;
• Combines the “do it loop
yourself join” with “do it the fetch c1 into l_data;
exit when c1%notfound;
hard way” to get the wrong open c2( l_data );
answer after a longer fetch c2 into l_something_else;
period of time with lots close c2;
more development time process( l_data, l_something_else);
end loop;
close c1;
Multi-Row Processing
• When others
• Autonomous Transactions
• Triggers
Things to do…
“Instrument your code. Make it debuggable. Make it so that tracing the
code is easy. Identify yourself with DBMS_SESSION. Now
DBMS_MONITOR can trace you. Add copious calls to
DBMS_APPLICATION_INFO, now we can see who you are, what you
are doing and how long you’ve been doing it. Add calls to a logging
package (for example http://log4plsql.sourceforge.net/) to enable remote
debugging of your code. Use conditional compilation to enable extra
intensive debug code to be ‘deployed’ to production.”
“Use the tools – SQL Developer, built in source code
debugging. Hierarchical profiling – for performance. Tracing
tools to see how your SQL is doing. ASH/AWR reports.
PL/SCOPE. Learn the tools, then use them.”
“Always test things out – especially advice. I used to advise to use
BULK COLLECT for everything. That changed in Oracle Database
10g when they started implicitly doing that for us. There is advice on
the ‘internet’ to never use implicit cursor – always use explicit. It is
wrong. If they suggest it is “faster” and you cannot see it being
“faster”, question the advice.”
“Question Authority, Ask Questions”