Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005

rekharaghuram
from rekharaghuram More from this publisher
05.11.2015 Views

CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS 13 Let’s now compare the two approaches in detail with runstats, a simple tool I’ve developed: ■Note For details on setting up runstats and other utilities, please see the “Setting Up” section at the beginning of this book. ops$tkyte@ORA9IR2> exec runstats_pkg.rs_start PL/SQL procedure successfully completed. ops$tkyte@ORA9IR2> exec proc1 PL/SQL procedure successfully completed. ops$tkyte@ORA9IR2> exec runstats_pkg.rs_middle PL/SQL procedure successfully completed. ops$tkyte@ORA9IR2> exec proc2 PL/SQL procedure successfully completed. ops$tkyte@ORA9IR2> exec runstats_pkg.rs_stop(1000) Run1 ran in 159 hsecs Run2 ran in 516 hsecs run 1 ran in 30.81% of the time Now, that result clearly shows that by the wall clock, proc2, which did not use a bind variable, took significantly longer to insert 10,000 rows than proc1, which did. In fact, proc2 took three times longer, meaning that, in this case, for every “non-bind-variable” INSERT, we spent two-thirds of the time to execute the statement simply parsing the statement! ■Note If you like, you can run the example in this section without runstats by issuing SET TIMING ON in SQL*Plus and running proc1 and proc2 as well. But the news gets even worse for proc2. The runstats utility produces a report that shows the actual values and calculates the differences in latch utilization, as well as statistics such as number of parses. Here I asked runstats to print out anything with a difference greater than 1,000 (that is the meaning of the 1000 in the rs_stop call). When we look at this information, we can see a significant difference in the resources used by each approach: Name Run1 Run2 Diff STAT...parse count (hard) 4 10,003 9,999 LATCH.library cache pin 80,222 110,221 29,999 LATCH.library cache pin alloca 40,161 80,153 39,992 LATCH.row cache enqueue latch 78 40,082 40,004 LATCH.row cache objects 98 40,102 40,004

14 CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS LATCH.child cursor hash table 35 80,023 79,988 LATCH.shared pool 50,455 162,577 112,122 LATCH.library cache 110,524 250,510 139,986 Run1 latches total versus runs -- difference and pct Run1 Run2 Diff Pct 407,973 889,287 481,314 45.88% PL/SQL procedure successfully completed. ■Note It is to be expected that you see somewhat different values in your testing. I would be surprised if you got exactly the same values for all numbers, especially the latching numbers. You should, however, see similar numbers, assuming you are using Oracle9i Release 2 on Linux, as I was here. In all releases, I would expect the number of latches used to hard parse to be higher than those for soft parsing each insert, or parsing the insert once and executing it over and over. Running the preceding test in Oracle 10g Release 1 on the same machine produced results such that the elapsed time of the bind variable approach was onetenth of the non–bind variable approach, and the amount of latches taken was 17 percent. This was due to two factors, one being that 10g is a new release and some internal algorithms changed. The other was due to an improved way dynamic SQL is processed in PL/SQL in 10g. You can see that there were only four hard parses with the bind variable approach, but over 10,000 hard parses without bind variables (once for each of the inserts). But that is just the tip of the iceberg. You can see here that twice as many “latches” were used in the non–bind variable approach than when using bind variables. This is because in order to modify this shared structure, Oracle must take care to allow only one process in at a time (it is very bad if two processes or threads attempt to update the same in-memory data structure simultaneously—corruption would abound). So, Oracle employs a latching mechanism, a lightweight locking device, to serialize access. Don’t be fooled by the word “lightweight”—these are serialization devices, allowing one-at-a-time, short duration access to a data structure. The latches overused by the hard-parsing implementation are among the most used latches out there. The latch into the shared pool and the latch for the library cache are big-time latches; they’re the ones that people compete for frequently. What that means is that as we increase the number of users attempting to hard-parse statements simultaneously, our performance problem will get progressively worse over time. The more people parsing, the more people fighting for the right to latch the shared pool, the longer the queues, the longer the wait. ■Note In 9i and above on machines with more than one processor, the shared pool may be divided into multiple subpools, each protected by its own latch. This permits increased scalability for applications that do not use bind variables, but it does not make the latching problem go away by any means.

CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS 13<br />

Let’s now compare the two approaches in detail with runstats, a simple tool I’ve developed:<br />

■Note For details on setting up runstats <strong>and</strong> other utilities, please see the “Setting Up” section at the<br />

beginning of this book.<br />

ops$tkyte@ORA9IR2> exec runstats_pkg.rs_start<br />

PL/SQL procedure successfully completed.<br />

ops$tkyte@ORA9IR2> exec proc1<br />

PL/SQL procedure successfully completed.<br />

ops$tkyte@ORA9IR2> exec runstats_pkg.rs_middle<br />

PL/SQL procedure successfully completed.<br />

ops$tkyte@ORA9IR2> exec proc2<br />

PL/SQL procedure successfully completed.<br />

ops$tkyte@ORA9IR2> exec runstats_pkg.rs_stop(1000)<br />

Run1 ran in 159 hsecs<br />

Run2 ran in 516 hsecs<br />

run 1 ran in 30.81% of the time<br />

Now, that result clearly shows that by the wall clock, proc2, which did not use a bind variable,<br />

took significantly longer to insert 10,000 rows than proc1, which did. In fact, proc2 took<br />

three times longer, meaning that, in this case, for every “non-bind-variable” INSERT, we spent<br />

two-thirds of the time to execute the statement simply parsing the statement!<br />

■Note If you like, you can run the example in this section without runstats by issuing SET TIMING ON in<br />

SQL*Plus <strong>and</strong> running proc1 <strong>and</strong> proc2 as well.<br />

But the news gets even worse for proc2. The runstats utility produces a report that shows<br />

the actual values <strong>and</strong> calculates the differences in latch utilization, as well as statistics such as<br />

number of parses. Here I asked runstats to print out anything with a difference greater than<br />

1,000 (that is the meaning of the 1000 in the rs_stop call). When we look at this information,<br />

we can see a significant difference in the resources used by each approach:<br />

Name Run1 Run2 Diff<br />

STAT...parse count (hard) 4 10,003 9,999<br />

LATCH.library cache pin 80,222 110,221 29,999<br />

LATCH.library cache pin alloca 40,161 80,153 39,992<br />

LATCH.row cache enqueue latch 78 40,082 40,004<br />

LATCH.row cache objects 98 40,102 40,004

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!