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 10 ■ DATABASE TABLES 359 ops$tkyte@ORA10GR1> begin 2 for x in ( select empno from emp ) 3 loop 4 for y in ( select emp.ename, a.street, a.city, a.state, a.zip 5 from emp, heap_addresses a 6 where emp.empno = a.empno 7 and emp.empno = x.empno ) 8 loop 9 null; 10 end loop; 11 end loop; 12 end; 13 / PL/SQL procedure successfully completed. Here, we are just emulating a busy period and running the query some 45,000 times, once for each EMPNO. If we run that for the HEAP_ADRESSES and IOT_ADDRESSES tables, TKPROF shows us the following: SELECT EMP.ENAME, A.STREET, A.CITY, A.STATE, A.ZIP FROM EMP, HEAP_ADDRESSES A WHERE EMP.EMPNO = A.EMPNO AND EMP.EMPNO = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 48244 7.66 7.42 0 0 0 0 Fetch 48244 6.29 6.56 0 483393 0 192976 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 96489 13.95 13.98 0 483393 0 192976 Rows Row Source Operation ------- --------------------------------------------------- 192976 NESTED LOOPS (cr=483393 pr=0 pw=0 time=5730335 us) 48244 TABLE ACCESS BY INDEX ROWID EMP (cr=144732 pr=0 pw=0 time=1594981 us) 48244 INDEX UNIQUE SCAN EMP_PK (cr=96488 pr=0 pw=0 time=926147 us)... 192976 TABLE ACCESS BY INDEX ROWID HEAP_ADDRESSES (cr=338661 pr=0 pw=0 time=... 192976 INDEX RANGE SCAN SYS_C008073 (cr=145685 pr=0 pw=0 time=1105135 us)... ******************************************************************************** SELECT EMP.ENAME, A.STREET, A.CITY, A.STATE, A.ZIP FROM EMP, IOT_ADDRESSES A WHERE EMP.EMPNO = A.EMPNO AND EMP.EMPNO = :B1 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 48244 8.17 8.81 0 0 0 0 Fetch 48244 4.31 4.12 0 292918 0 192976

360 CHAPTER 10 ■ DATABASE TABLES ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 96489 12.48 12.93 0 292918 0 192976 Rows Row Source Operation ------- --------------------------------------------------- 192976 NESTED LOOPS (cr=292918 pr=0 pw=0 time=3429753 us) 48244 TABLE ACCESS BY INDEX ROWID EMP (cr=144732 pr=0 pw=0 time=1615024 us) 48244 INDEX UNIQUE SCAN EMP_PK (cr=96488 pr=0 pw=0 time=930931 us)... 192976 INDEX RANGE SCAN SYS_IOT_TOP_59607 (cr=148186 pr=0 pw=0 time=1417238 us)... Both queries fetched exactly the same number of rows, but the HEAP table performed considerably more logical I/O. As the degree of concurrency on the system goes up, we would likewise expect the CPU used by the HEAP table to go up more rapidly as well, while the query possibly waits for latches into the buffer cache. Using runstats (a utility of my own design), we can measure the difference in latching. On my system, I observed the following: STAT...consistent gets 484,065 293,566 -190,499 STAT...no work - consistent re 194,546 4,047 -190,499 STAT...consistent gets from ca 484,065 293,566 -190,499 STAT...session logical reads 484,787 294,275 -190,512 STAT...table fetch by rowid 241,260 48,260 -193,000 STAT...buffer is not pinned co 337,770 96,520 -241,250 LATCH.cache buffers chains 732,960 349,380 -383,580 Run1 latches total versus runs -- difference and pct Run1 Run2 Diff Pct 990,344 598,750 -391,594 165.40% where Run1 was the HEAP_ADDRESSES table and Run2 was the IOT_ADDRESSES table. As you can see, there was a dramatic and repeatable decrease in the latching taking place, mostly due to the cache buffers chains latch (the one that protects the buffer cache). The IOT in this case would provide the following benefits: • Increased buffer cache efficiency, as any given query needs to have fewer blocks in the cache • Decreased buffer cache access, which increases scalability • Less overall work to retrieve our data, as it is faster • Less physical I/O per query possibly, as fewer distinct blocks are needed for any given query and a single physical I/O of the addresses most likely retrieves all of them (not just one of them, as the heap table implementation does) The same would be true if you frequently use BETWEEN queries on a primary or unique key. Having the data stored physically sorted will increase the performance of those queries as well. For example, I maintain a table of stock quotes in my database. Every day, for hundreds of stocks, I gather together the stock ticker, date, closing price, days high, days low, volume, and other related information. The table looks like this:

CHAPTER 10 ■ DATABASE TABLES 359<br />

ops$tkyte@ORA10GR1> begin<br />

2 for x in ( select empno from emp )<br />

3 loop<br />

4 for y in ( select emp.ename, a.street, a.city, a.state, a.zip<br />

5 from emp, heap_addresses a<br />

6 where emp.empno = a.empno<br />

7 <strong>and</strong> emp.empno = x.empno )<br />

8 loop<br />

9 null;<br />

10 end loop;<br />

11 end loop;<br />

12 end;<br />

13 /<br />

PL/SQL procedure successfully completed.<br />

Here, we are just emulating a busy period <strong>and</strong> running the query some 45,000 times, once<br />

for each EMPNO. If we run that for the HEAP_ADRESSES <strong>and</strong> IOT_ADDRESSES tables, TKPROF shows us<br />

the following:<br />

SELECT EMP.ENAME, A.STREET, A.CITY, A.STATE, A.ZIP<br />

FROM EMP, HEAP_ADDRESSES A<br />

WHERE EMP.EMPNO = A.EMPNO AND EMP.EMPNO = :B1<br />

call count cpu elapsed disk query current rows<br />

------- ------ -------- ---------- ---------- ---------- ---------- ----------<br />

Parse 1 0.00 0.00 0 0 0 0<br />

Execute 48244 7.66 7.42 0 0 0 0<br />

Fetch 48244 6.29 6.56 0 483393 0 192976<br />

------- ------ -------- ---------- ---------- ---------- ---------- ----------<br />

total 96489 13.95 13.98 0 483393 0 192976<br />

Rows Row Source Operation<br />

------- ---------------------------------------------------<br />

192976 NESTED LOOPS (cr=483393 pr=0 pw=0 time=5730335 us)<br />

48244 TABLE ACCESS BY INDEX ROWID EMP (cr=144732 pr=0 pw=0 time=1594981 us)<br />

48244 INDEX UNIQUE SCAN EMP_PK (cr=96488 pr=0 pw=0 time=926147 us)...<br />

192976 TABLE ACCESS BY INDEX ROWID HEAP_ADDRESSES (cr=338661 pr=0 pw=0 time=...<br />

192976 INDEX RANGE SCAN SYS_C008073 (cr=145685 pr=0 pw=0 time=1105135 us)...<br />

********************************************************************************<br />

SELECT EMP.ENAME, A.STREET, A.CITY, A.STATE, A.ZIP<br />

FROM EMP, IOT_ADDRESSES A<br />

WHERE EMP.EMPNO = A.EMPNO AND EMP.EMPNO = :B1<br />

call count cpu elapsed disk query current rows<br />

------- ------ -------- ---------- ---------- ---------- ---------- ----------<br />

Parse 1 0.00 0.00 0 0 0 0<br />

Execute 48244 8.17 8.81 0 0 0 0<br />

Fetch 48244 4.31 4.12 0 292918 0 192976

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

Saved successfully!

Ooh no, something went wrong!