25. Tuning PL/SQL Applications
Contents:
Tuning an application is a very complicated process. Really, it deserves a book of its own. Fortunately, there is such a book: Oracle Performance Tuning by Mark Gurry and Peter Corrigan.[ 1 ] Many of the ideas in this section are drawn from -- and explored more thoroughly in -- Gurry and Corrigan's book.
Before diving into the particulars, I want to be sure that you recognize the different aspects of tuning PL/SQL that you might want to perform:
The following sections address each of these areas of PL/SQL tuning. 25.1 Analyzing Program PerformanceBefore you can tune your application, you need to know what is causing it to slow down. To do this, you usually need to be able to analyze the performance of your application. Oracle offers a number of database monitoring and diagnostic tools, as do third-party vendors like Platinum Technology and Quest. Check Oracle documentation and Chapter 10 of Oracle Performance Tuning for more details, and be aware of the following major tools:
25.1.1 Use the DBMS_UTILITY.GET_TIME FunctionThe tools listed in the previous section provide varying levels of detail and granularity; however, they all do require some effort -- often on the part of a person other than the PL/SQL developer in need -- to get them enabled. And then they require even more effort to interpret results. Don't get me wrong; I am not really complaining. It's just that, quite frankly, PL/SQL developers often want to examine the performance of a particular program and do not want to have to deal with all that other stuff. No problem! PL/SQL provides a mechanism to obtain timings of code execution that are accurate to 100th of a second: the DBMS_UTILTY.GET_TIME function. Yes, that's right. I said 100th of a second. For those of you who have programmed in Oracle over the past few years, this should be a welcome surprise. Before the advent of the DBMS_UTILITY package, the only way to measure elapsed time was to use SYSDATE and examine the difference in the time component. Sadly, this component only records times down to the nearest second. This doesn't help much when you need to measure subsecond response time. DBMS_UTILTY.GET_TIME returns the number of hundredths of seconds which have elapsed since some arbitrary point in time. I don't remember what that point is and, well, that's the whole point. A single value returned by a call to dbms_utility.get_time is, by itself, meaningless. If, on the other hand, you call this built-in function twice and then take the difference between the two returned values, you will have determined the number of hundredths of seconds which elapsed between the two calls. So if you sandwich the execution of your own program between calls to DBMS_UTILTY.GET_TIME, you will have discovered how long it takes to run that program. The anonymous block below shows how to use GET_TIME to determine the time it takes to perform the calc_totals procedure: DECLARE time_before BINARY_INTEGER; time_after BINARY_INTEGER; BEGIN time_before := DBMS_UTILITY.GET_TIME; calc_totals; time_after := DBMS_UTILITY.GET_TIME; DBMS_OUTPUT.PUT_LINE (time_after - time_before); END; I found myself relying on GET_TIME frequently as I developed the code in this book, because I wanted to analyze the performance impact of a particular approach or technique. Is it faster to raise an exception or execute an IF statement? Is it faster to load 100 rows in a table or concatenate 100 substrings into a long string? There are two basic approaches you can take to using this handy function:
You will find on the companion disk an explanation and code for such a package, sp_timer, in the files sptimer.sps and sptimer.spb. In addition, you will find in Advanced Oracle PL/SQL Programming with Packages a more complete performance timing utility based on DBMS_UTILITY.GET_TIME in the PLVtmr package. Once you have encapsulated your usage of DBMS_UTILITY.GET_TIME, it is very easy to put together scripts which not only analyze performance, but also compare different implementations. The following script, for example, executes two different versions of the is_number function (see " Section 25.4, "Tuning Your Algorithms" " for more information on this function) and displays the resulting elapsed times (using the PLVtmr and p packages from the PL/Vision library; again, see Advanced Oracle PL/SQL Programming with Packages : SET VERIFY OFF DECLARE b BOOLEAN; BEGIN PLVtmr.set_factor (&1) PLVtmr.capture; FOR repind IN 1 .. &1 -- Number of iterations LOOP b := isnum ('&2'); -- The string to test IF repind = 1 THEN p.l (b); END IF; END LOOP; PLVtmr.show_elapsed (`TO_NUMBER Version'); PLVtmr.set_factor (&1) PLVtmr.capture; FOR repind IN 1 .. &1 LOOP b := isnum_translate ('&2'); PLVtmr.last_timing := 15; IF repind = 1 THEN p.l (b); END IF; END LOOP; PLVtmr.show_elapsed (`TRANSLATE Version'); END; / Copyright (c) 2000 O'Reilly & Associates. All rights reserved. |
|