Apress.Expert.Oracle.Database.Architecture.9i.and.10g.Programming.Techniques.and.Solutions.Sep.2005
CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS 43 ops$tkyte@ORA10G> select /* TAG */ substr( username, 1, 1 ) 2 from all_users au1 3 where rownum = 1; S - B ops$tkyte@ORA10G> alter session set cursor_sharing=force; Session altered. ops$tkyte@ORA10G> select /* TAG */ substr( username, 1, 1 ) 2 from all_users au2 3 where rownum = 1; SUBSTR(USERNAME,1,1) ------------------------------ B What happened there? Why is the column reported by SQL*Plus suddenly so large for the second query, which is arguably the same query? If we look at what the cursor sharing setting did for us, it (and something else) will become obvious: ops$tkyte@ORA10G> select sql_text from v$sql 2 where sql_text like 'select /* TAG */ %'; SQL_TEXT ------------------------------------------------------------------------------- select /* TAG */ substr( username, 1, 1 ) from all_users au1 where rownum = 1 select /* TAG */ substr( username, :"SYS_B_0", :"SYS_B_1" ) 2 where rownum = :"SYS_B_2" from all_users au The cursor sharing removed information from the query. It found every literal, including the parameters to the built-in substring function, which were constants we were using. It removed them from the query and replaced them with bind variables. The SQL engine no longer knows that the column is a substring of length 1—it is of indeterminate length. Also, you can see that where rownum = 1 is now bound as well. That seems like a good idea; however, the optimizer has just had some important information removed. It no longer knows that “this query will retrieve a single row”; it now believes “this query will return the first N rows and N could be any number at all.” In fact, if you run these queries with SQL_TRACE=TRUE, you will find the query plans used by each query and the amount of work they perform to be very different. Consider the following: select /* TAG */ substr( username, 1, 1 ) from all_users au1 where rownum = 1
44 CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 0 77 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 0 77 0 1 Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 412 Rows Row Source Operation ------- --------------------------------------------------- 1 COUNT STOPKEY (cr=77 pr=0 pw=0 time=5767 us) 1 HASH JOIN (cr=77 pr=0 pw=0 time=5756 us) 1028 HASH JOIN (cr=70 pr=0 pw=0 time=8692 us) 9 TABLE ACCESS FULL TS$ (cr=15 pr=0 pw=0 time=335 us) 1028 TABLE ACCESS FULL USER$ (cr=55 pr=0 pw=0 time=2140 us) 4 TABLE ACCESS FULL TS$ (cr=7 pr=0 pw=0 time=56 us) ******************************************************************************** select /* TAG */ substr( username, :"SYS_B_0", :"SYS_B_1" ) from all_users au2 where rownum = :"SYS_B_2" call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 0 85 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 0 85 0 1 Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 412 Rows Row Source Operation ------- --------------------------------------------------- 1 COUNT (cr=85 pr=0 pw=0 time=3309 us) 1 FILTER (cr=85 pr=0 pw=0 time=3301 us) 1028 HASH JOIN (cr=85 pr=0 pw=0 time=5343 us) 1028 HASH JOIN (cr=70 pr=0 pw=0 time=7398 us) 9 TABLE ACCESS FULL TS$ (cr=15 pr=0 pw=0 time=148 us) 1028 TABLE ACCESS FULL USER$ (cr=55 pr=0 pw=0 time=1079 us) 9 TABLE ACCESS FULL TS$ (cr=15 pr=0 pw=0 time=90 us)
- Page 38 and 39: ■SETTING UP YOUR ENVIRONMENT xxxv
- Page 40 and 41: ■SETTING UP YOUR ENVIRONMENT xxxi
- Page 42 and 43: ■SETTING UP YOUR ENVIRONMENT xli
- Page 44 and 45: ■SETTING UP YOUR ENVIRONMENT xlii
- Page 46 and 47: CHAPTER 1 ■ ■ ■ Developing Su
- Page 48 and 49: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 50 and 51: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 52 and 53: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 54 and 55: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 56 and 57: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 58 and 59: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 60 and 61: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 62 and 63: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 64 and 65: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 66 and 67: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 68 and 69: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 70 and 71: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 72 and 73: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 74 and 75: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 76 and 77: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 78 and 79: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 80 and 81: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 82 and 83: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 84 and 85: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 86 and 87: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 90 and 91: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 92: CHAPTER 1 ■ DEVELOPING SUCCESSFUL
- Page 95 and 96: 50 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 97 and 98: 52 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 99 and 100: 54 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 101 and 102: 56 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 103 and 104: 58 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 105 and 106: 60 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 107 and 108: 62 CHAPTER 2 ■ ARCHITECTURE OVERV
- Page 110 and 111: CHAPTER 3 ■ ■ ■ Files In this
- Page 112 and 113: CHAPTER 3 ■ FILES 67 Without a pa
- Page 114 and 115: CHAPTER 3 ■ FILES 69 and even dat
- Page 116 and 117: CHAPTER 3 ■ FILES 71 all operatio
- Page 118 and 119: CHAPTER 3 ■ FILES 73 *.cluster_da
- Page 120 and 121: CHAPTER 3 ■ FILES 75 ops$tkyte@OR
- Page 122 and 123: CHAPTER 3 ■ FILES 77 • To maint
- Page 124 and 125: CHAPTER 3 ■ FILES 79 • Resource
- Page 126 and 127: CHAPTER 3 ■ FILES 81 3 l_dummy nu
- Page 128 and 129: CHAPTER 3 ■ FILES 83 Trace Files
- Page 130 and 131: CHAPTER 3 ■ FILES 85 _qerixAlloca
- Page 132 and 133: CHAPTER 3 ■ FILES 87 6 ( 7 TYPE O
- Page 134 and 135: CHAPTER 3 ■ FILES 89 A Brief Revi
- Page 136 and 137: CHAPTER 3 ■ FILES 91 Redundant Ar
CHAPTER 1 ■ DEVELOPING SUCCESSFUL ORACLE APPLICATIONS 43<br />
ops$tkyte@ORA10G> select /* TAG */ substr( username, 1, 1 )<br />
2 from all_users au1<br />
3 where rownum = 1;<br />
S<br />
-<br />
B<br />
ops$tkyte@ORA10G> alter session set cursor_sharing=force;<br />
Session altered.<br />
ops$tkyte@ORA10G> select /* TAG */ substr( username, 1, 1 )<br />
2 from all_users au2<br />
3 where rownum = 1;<br />
SUBSTR(USERNAME,1,1)<br />
------------------------------<br />
B<br />
What happened there? Why is the column reported by SQL*Plus suddenly so large for the<br />
second query, which is arguably the same query? If we look at what the cursor sharing setting<br />
did for us, it (<strong>and</strong> something else) will become obvious:<br />
ops$tkyte@ORA10G> select sql_text from v$sql<br />
2 where sql_text like 'select /* TAG */ %';<br />
SQL_TEXT<br />
-------------------------------------------------------------------------------<br />
select /* TAG */ substr( username, 1, 1 ) from all_users au1 where rownum =<br />
1<br />
select /* TAG */ substr( username, :"SYS_B_0", :"SYS_B_1" )<br />
2 where rownum = :"SYS_B_2"<br />
from all_users au<br />
The cursor sharing removed information from the query. It found every literal, including<br />
the parameters to the built-in substring function, which were constants we were using. It<br />
removed them from the query <strong>and</strong> replaced them with bind variables. The SQL engine no<br />
longer knows that the column is a substring of length 1—it is of indeterminate length. Also,<br />
you can see that where rownum = 1 is now bound as well. That seems like a good idea; however,<br />
the optimizer has just had some important information removed. It no longer knows that “this<br />
query will retrieve a single row”; it now believes “this query will return the first N rows <strong>and</strong> N<br />
could be any number at all.” In fact, if you run these queries with SQL_TRACE=TRUE, you will find<br />
the query plans used by each query <strong>and</strong> the amount of work they perform to be very different.<br />
Consider the following:<br />
select /* TAG */ substr( username, 1, 1 )<br />
from all_users au1<br />
where rownum = 1