Oracle query processing and optimization basics

11,097 views
10,870 views

Published on

Fundamentals of oracle query processing and optimization basics

0 Comments
30 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
11,097
On SlideShare
0
From Embeds
0
Number of Embeds
93
Actions
Shares
0
Downloads
0
Comments
0
Likes
30
Embeds 0
No embeds

No notes for slide
  • How Oracle uses these stats (no histogram)?Filtering predicate selectivity = 1 / ndv (density)Filter cardinality = #of Rows /ndv (number of rows selected by the filter)Group cardinality = ndv (the number of rows produced from a row set after the GROUP BY operator is applied)
  • Oracle query processing and optimization basics

    1. 1. Query Processing and OptimizationBasics in Oracle <br />Fatih Emekci<br />
    2. 2. Life of a Query<br />
    3. 3. Life of a Query<br />Query rewrite (View merging etc.)<br />Access path, join order, join type<br />Selectivity estimation, join size estimation, cardinality estimation<br />
    4. 4. Life of a Query<br />
    5. 5. Life of a Query<br />
    6. 6. Agenda<br />Statistics<br />How Oracle estimates?<br />Access Paths<br />How Oracle retrieves data from disk?<br />Join types and their implementations<br />Major query transformations<br />How to understand and tune the queries?<br />Some query writing tips<br />How to write efficient SQL queries?<br />
    7. 7. Basic Statistics<br /><ul><li>Table statistics
    8. 8. Number of rows
    9. 9. Number of blocks
    10. 10. Average row length
    11. 11. Column statistics
    12. 12. Number of distinct values (NDV
    13. 13. Number of nulls
    14. 14. Data distribution (histogram)
    15. 15. Index statistics
    16. 16. Number of leaf blocks
    17. 17. Levels
    18. 18. Clustering factor</li></ul>DBA_TABLES<br />DBA_TAB_COL_STATISTICS<br />DBA_INDEXES<br />
    19. 19. Most important stats<br /><ul><li>Number of distinct value (ndv), number of rows, number of null rows, histograms
    20. 20. Join size after each join (Join ordering, join method)
    21. 21. Selectivity of a filtering predicate (last_name = ‘Smith’)
    22. 22. Cardinality estimation
    23. 23. How Oracle uses these stats (no histogram)?
    24. 24. Filtering predicate selectivity = 1 / ndv
    25. 25. Filter cardinality = #of Rows /ndv
    26. 26. Group cardinality = ndv</li></li></ul><li>Join cardinality estimation<br />Oracle assumes all joins are like fact table and dimension table joins<br />Sales (CityID [FK on Cities], ItemID,Date, ……)<br />Cities(CityID [PK], CityName, ……) <br />Select * from Sales, Cities where Sales.CityID = Cities.CityID<br />Join cardinality?<br /> (# of rows in Cities) x (#of rows in Sales)<br />Max( ndv of Cities.CityID, ndv of Sales.CityID)<br />
    27. 27. Join ordering<br />Very important. Why?<br />Select * <br />From Customer, Orders, Item, Product<br />Where ……..<br />
    28. 28. Ndv used to be a big pain<br /><ul><li>The hearth of all computations
    29. 29. Select distinct (cityID) from sales
    30. 30. Very expensive
    31. 31. Too many columns and tables
    32. 32. Stats are derived from samples
    33. 33. How much to sample?
    34. 34. To compute accurate enough ndv ?
    35. 35. Sampling does not help (Need to sample almost all the rows to give some error guarantee)
    36. 36. Random Sampling for Histogram Construction: How much is enough? (SIGMOD 1998)
    37. 37. 11G computes ndv’s with a full table scan using a probabilistic counting algorithm
    38. 38. Probabilistic Counting Algorithms for Data Base Applications (Flajalet & Martin 1985)
    39. 39. Let Oracle does ndv computation for you
    40. 40. Do not use sampling </li></li></ul><li>Histograms<br /><ul><li>A 254 bucket histogram is built
    41. 41. If data is skewed
    42. 42. Used in selectivity estimation
    43. 43. Two types of histograms
    44. 44. Frequency histograms if ndv < 254
    45. 45. Height-balanced histograms
    46. 46. Can be viewed by DBA_HISTOGRAM
    47. 47. Column statistics are useful for join order, type
    48. 48. More accurate estimation of number of rows
    49. 49. A small sample is enough to derive histograms
    50. 50. How are histograms used?</li></li></ul><li>Illustration of histograms<br />Select endpoint_number, endpoint_value<br />from DBA_HISTOGRAMS <br />where table_name =“T1” and column_name = “C1”<br />ENDPOINT_NUMBER ENDPOINT_VALUE<br />--------------- ---------------<br /> 1 4<br /> 2 5<br /> 9 8<br /> ….. ….<br /> 254 197878<br />Select * from T1 c1 = 8 =&gt; selectivity is 7/254<br />
    51. 51. Reading Stats<br />
    52. 52. Major Table Access Methods<br />Full Table Scans<br />Large # of rows<br />Small tables<br />High degree of parallelism<br />Cheaper since continues read and fewer I/O calls<br />Rowid Scans<br />The rowid of a row specifies location of a row<br /> Fastest way to retrieve a single row (or a few rows)<br />
    53. 53. Index Scans<br /><ul><li>Index Unique Scans
    54. 54. For primary key and unique cols
    55. 55. Index Range Scans
    56. 56. For secondary indexes (index on the last name)
    57. 57. Range predicates
    58. 58. Index Skip Scans
    59. 59. Composite index and predicate is not leading the index
    60. 60. Index on (gender, age) and predicate is age > 20
    61. 61. Can be parallel
    62. 62. Full Scans
    63. 63. Ordered scan of all keys in the index
    64. 64. Fast Full Index Scans
    65. 65. Parallel unordered scan of all keys</li></li></ul><li>Reading access paths<br />
    66. 66. Joins<br />There are three types of joins<br />Nested loop<br />Hash join <br />Sort-merge join<br />You can force with hints<br />use_nl(table1,table2), use_hash(table1, table2)<br />SELECT /*+ USE_NL(customers, accounts) */ *<br />FROM accounts, customers<br />WHERE accounts.customer_id = customers.customer_id;<br />
    67. 67. Nested Loops<br />Select * from R, S <br /> where R.rid=S.sid (predicate p) <br />for each block of R, and for each r in the block: <br />for each block of S, and for each s in the block: <br />Output rs if p evaluates to true over r and s <br />R is called the outer-table; <br />S is called the inner-table <br />I/O’s: B(R) + |R| ⋅B(S) <br />Usually inner table has an index<br />Used when # of rows to join is small<br />Less than 10K<br />
    68. 68. Nested loops in the plan<br />
    69. 69. Sort-merge join<br />Sort R and S by their join attributes, and then merge r, s<br /> I/O’s: sorting + 2 B(R) + 2 B(S)<br />The cost of external sorting is very high<br />The algorithm where M is the memory size<br />Get M blocks, sort and write to the disk<br />Merge sorted blocks in log MB(R) steps<br />The I/O cost is<br /> O( B(R) ⋅log MB(R) ) where M is the memory size<br />Usually used when data is sorted<br />
    70. 70. Sort-merge join optimization<br />If you have enough memory<br />The I/O cost 3 x (B(R) + B(S))<br />Memory requirement<br /> M &gt; Sqrt(B(R) + B(S))<br />
    71. 71. SMJ in the plan<br />SQL&gt; explain plan for select /*+ use_merge (sch, mem) */ education_id, start_date, sch. code from schools sch, member_schools mem where sch.school_id = mem.school_id;<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />-------------------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |<br />-------------------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 1 | 46 | | 92 (4)| 00:00:02 |<br />| 1 | MERGE JOIN | | 1 | 46 | | 92 (4)| 00:00:02 |<br />| 2 | SORT JOIN | | 1 | 39 | | 18 (6)| 00:00:01 |<br />| 3 | TABLE ACCESS FULL| MEMBER_SCHOOLS | 1 | 39 | | 17 (0)| 00:00:01 |<br />|* 4 | SORT JOIN | | 10404 | 72828 | 344K| 74 (3)| 00:00:01 |<br />| 5 | TABLE ACCESS FULL| SCHOOLS | 10404 | 72828 | | 35 (0)| 00:00:01 |<br />-------------------------------------------------------------------------------------------------<br />
    72. 72. Sort based operations<br />Set operations<br />Union, intersection, difference<br />Very similar to sort-merge join<br />Duplicate elimination<br />External sorting<br />Why are UNION and DISTINCT expensive?<br />Group-by-aggregation queries<br />External sorting is needed<br />Very very expensive when partial aggregation is not possible (e.g. MEDIAN)<br />
    73. 73. Hash join<br />Load the smaller relation in a hash table (virtual memory) <br />Probe the bigger table<br />The cost = B(R) + B(S)<br />Used when number of rows to join is large and sorting is not needed<br />
    74. 74. Hash join in the plan<br />SQL&gt; explain plan for select /*+ ordered use_hash (sch, mem) */ education_id, start_date, sch. code from schools sch, member_ schools mem where sch.school_id = mem.school_id;<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />----------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />----------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 1 | 46 | 53 (2)| 00:00:01 |<br />|* 1 | HASH JOIN | | 1 | 46 | 53 (2)| 00:00:01 |<br />| 2 | TABLE ACCESS FULL| SCHOOLS | 10404 | 72828 | 35 (0)| 00:00:01 |<br />| 3 | TABLE ACCESS FULL| MEMBER_SCHOOLS | 1 | 39 | 17 (0)| 00:00:01 |<br />----------------------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 1 - access(&quot;SCH&quot;.&quot;SCHOOL_ID&quot;=&quot;MEM&quot;.&quot;SCHOOL_ID&quot;)<br />
    75. 75. Major query transformations<br /><ul><li>View Merging
    76. 76. Create view v as select S.sname as sname, R.rname as rname from R,S where R.rid = S.Sid
    77. 77. Select * from v, T where v.sname = T.tname
    78. 78. Select S.sname, R.rname, T.* from R, S, T where R.rid = S.Sid and S.sname = T.tname
    79. 79. Can find a more efficient join order
    80. 80. Cannot merge every view
    81. 81. Predicate Pushing
    82. 82. SubqueryUnnesting
    83. 83. Query Rewrite with Materialized Views
    84. 84. Star transformation
    85. 85. Deserves much more time !!!!!!!</li></li></ul><li>Why bad plan?<br />Stale statistics<br />Algorithmic limitations and corner cases<br />Histogram endpoints (endpoint is really bucket or just happen to be an endpoint?)<br />Wrong estimation and propagating this error<br />One wrong cardinality estimation or selectivity estimation<br />What to do?<br />Compare execution stats with optimization stats<br />
    86. 86. Execution vs. estimation stats<br />SQL&gt; select /*+ gather_plan_statistics */ empno from scott.emp e where e.empno &gt; 7600;<br />SQL&gt; select * from table(dbms_xplan.display_cursor(null, null, &apos;ALLSTATS LAST&apos;));<br />PLAN_TABLE_OUTPUT<br />------------------------------------------------------------------<br />| Id | Operation | Name | E-Rows | A-Rows|<br />------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 8 | 24 |<br />|* 1 | INDEX RANGE SCAN| PK_EMP | 8 | 24 |<br />-------------------------------------------------------------------<br />
    87. 87. Adjusting optimizer estimations<br />SQL&gt; select /*+ opt_estimate (table, e, scale_rows=1) */ empno from scott.emp e where e.empno &gt; 7600;<br />----------------------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />----------------------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 8 | 16 | 1 (0) | 00:00:01 |<br />|* 1 | INDEX RANGE SCAN| PK_EMP | 8 | 16 | 1 (0) | 00:00:01 |<br />------------------------------------------------------------------------------------------------------<br />SQL&gt; select /*+ opt_estimate (table, e, scale_rows=3.0) */ empno from scott.emp e where e.empno &gt; 7600;<br />--------------------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />--------------------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 24 | 16 | 1 (0) | 00:00:01 |<br />|* 1 | INDEX RANGE SCAN| PK_EMP | 24 | 16 | 1 (0) | 00:00:01 |<br />------------------------------------------------------------------------------------------------------<br />
    88. 88. Tip1 : Use Rownum for Boolean Checks<br />Is there any object with obj# &lt; 34000?<br />SQL&gt; explain plan for select count(*) from obj$ where obj# &lt; 34000;<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />PLAN_TABLE_OUTPUT<br />---------------------------------------------<br />Plan hash value: 3951003077<br />--------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />--------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 1 | 5 | 34 (3)| 00:00:01 |<br />| 1 | SORT AGGREGATE | | 1 | 5 | | |<br />|* 2 | INDEX FAST FULL SCAN| I_OBJ1 | 23254 | 113K| 34 (3)| 00:00:01 |<br />--------------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 2 - filter(&quot;OBJ#&quot;&lt;34000)<br />14 rows selected.<br />
    89. 89. Tip1 : Use Rownum for Boolean Checks<br />SQL&gt; explain plan for select count(*) from obj$ where obj# &lt; 34000 and rownum &lt; 2;<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />PLAN_TABLE_OUTPUT<br />---------------------------------------------<br />Plan hash value: 363927127<br />---------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />---------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 1 | 5 | 34 (3)| 00:00:01 |<br />| 1 | SORT AGGREGATE | | 1 | 5 | | |<br />|* 2 | COUNT STOPKEY | | | | | |<br />|* 3 | INDEX FAST FULL SCAN| I_OBJ1 | 23254 | 113K| 34 (3)| 00:00:01 |<br />---------------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 2 - filter(ROWNUM&lt;2)<br /> 3 - filter(&quot;OBJ#&quot;&lt;34000)<br />16 rows selected.<br />
    90. 90. Tip2 : Use UNION ALL Instead of UNION<br />SQL&gt; explain plan for (select * from obj$ where obj# &lt; 34000 UNION select * from obj$ where obj# &gt; 34000);<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />PLAN_TABLE_OUTPUT<br />---------------------------------------------<br />Plan hash value: 2397754038<br />------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |<br />------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 38781 | 2991K| | 977 (44)| 00:00:12 |<br />| 1 | SORT UNIQUE | | 38781 | 2991K| 9889K| 977 (44)| 00:00:12 |<br />| 2 | UNION-ALL | | | | | |<br />|* 3 | TABLE ACCESS FULL| OBJ$ | 23254 | 1794K| | 128 (1)| 00:00:02 |<br />|* 4 | TABLE ACCESS FULL| OBJ$ | 15527 | 1197K| | 128 (1)| 00:00:02 |<br />------------------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 3 - filter(&quot;OBJ#&quot;&lt;34000)<br /> 4 - filter(&quot;OBJ#&quot;&gt;34000)<br />17 rows selected.<br />
    91. 91. Tip2 : Use UNION ALL Instead of UNION<br />SQL&gt; explain plan for (select * from obj$ where obj# &lt; 34000 UNION ALL select * from obj$ where obj# &gt; 34000);<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />PLAN_TABLE_OUTPUT<br />---------------------------------------------<br />Plan hash value: 2386394847<br />---------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />---------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 38781 | 2991K| 257 (51)| 00:00:04 |<br />| 1 | UNION-ALL | | | | | |<br />|* 2 | TABLE ACCESS FULL| OBJ$ | 23254 | 1794K| 128 (1)| 00:00:02 |<br />|* 3 | TABLE ACCESS FULL| OBJ$ | 15527 | 1197K| 128 (1)| 00:00:02 |<br />---------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 2 - filter(&quot;OBJ#&quot;&lt;34000)<br /> 3 - filter(&quot;OBJ#&quot;&gt;34000)<br />16 rows selected.<br />
    92. 92. Tip3 : Eliminate Unnecessary Table Access<br />SQL&gt; explain plan for <br /> select education_id from member_ schools <br /> where school_name = (select max(name) from schools) <br /> and code = (select min(code) from schools);<br />Explained.<br />Elapsed: 00:00:00.03<br />SQL&gt; @?/rdbms/admin/utlxpls<br />PLAN_TABLE_OUTPUT<br />---------------------------------------------<br />Plan hash value: 2342446221<br />-------------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />-------------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 1 | 169 | 87 (0)| 00:00:02 |<br />|* 1 | TABLE ACCESS FULL | MEMBER_ SCHOOLS | 1 | 169 | 17 (0)| 00:00:01 |<br />| 2 | SORT AGGREGATE | | 1 | 36 | | |<br />| 3 | TABLE ACCESS FULL | SCHOOLS | 10404 | 365K| 35 (0)| 00:00:01 |<br />| 4 | SORT AGGREGATE | | 1 | 2 | | |<br />| 5 | TABLE ACCESS FULL| SCHOOLS | 10404 | 20808 | 35 (0)| 00:00:01 |<br />-------------------------------------------------------------------------------------------<br />
    93. 93. Tip3 : Eliminate Unnecessary Table Access<br />SQL&gt; explain plan for<br /> select education_id from member_schools<br /> where (school_name, code)=(select max(name), min(code) from schools);<br />SQL&gt; @?/rdbms/admin/utlxpls<br />-----------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />-----------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 1 | 469 | 72 (0)| 00:00:01 |<br />|* 1 | TABLE ACCESS FULL | MEMBER_SCHOOLS | 1 | 469 | 2 (0)| 00:00:01 |<br />| 2 | SORT AGGREGATE | | 1 | 456 | | |<br />| 3 | TABLE ACCESS FULL| SCHOOLS | 13728 | 6113K| 35 (0)| 00:00:01 |<br />-----------------------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 1 - filter((&quot;SCHOOL_NAME&quot;,&quot;CODE&quot;)= (SELECT<br /> MAX(&quot;NAME&quot;),MIN(&quot;CODE&quot;) FROM &quot;SCHOOLS&quot; &quot;SCHOOLS&quot;))<br />
    94. 94. Tip4 : Use Analytic Functions if Possible<br />SQL&gt; create table silly(day number, cumulative number);<br />Table created.<br />SQL&gt; insert into silly values (1,5);<br />1 row created.<br />SQL&gt; insert into silly values (2,10)<br /> 2 ;<br />1 row created.<br />SQL&gt; insert into silly values(3,15);<br />1 row created.<br />SQL&gt; insert into silly values(4,20);<br />1 row created.<br />SQL&gt; select * from silly;<br /> DAY CUMULATIVE<br /> ---------- ----------<br /> 1 5<br /> 2 10<br /> 3 15<br /> 4 20<br />Daily Report<br /> DAY TOTAL_FOR_THE_DAY<br /> ---------- -----------------<br /> 1 5<br /> 2 5<br /> 3 5<br /> 4 5<br />
    95. 95. Tip4 : Use Analytic Functions if Possible<br />SQL&gt; explain plan for <br /> select day, cumulative as total_for_the_day from silly where rownum =1 <br /> union all <br /> select t2.day, t2.cumulative - t1.cumulative as Total_For_the_Day <br /> from silly t1, silly t2 <br /> where t1.day = t2.day-1;<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />-----------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />-----------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 5 | 234 | 7 (72)| 00:00:01 |<br />| 1 | UNION-ALL | | | | | |<br />|* 2 | COUNT STOPKEY | | | | | |<br />| 3 | TABLE ACCESS FULL| SILLY | 4 | 104 | 2 (0)| 00:00:01 |<br />|* 4 | HASH JOIN | | 4 | 208 | 5 (20)| 00:00:01 |<br />| 5 | TABLE ACCESS FULL| SILLY | 4 | 104 | 2 (0)| 00:00:01 |<br />| 6 | TABLE ACCESS FULL| SILLY | 4 | 104 | 2 (0)| 00:00:01 |<br />-----------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 2 - filter(ROWNUM=1)<br /> 4 - access(&quot;T1&quot;.&quot;DAY&quot;=&quot;T2&quot;.&quot;DAY&quot;-1)<br />
    96. 96. Tip4 : Use Analytic Functions if Possible<br />SQL&gt; explain plan for <br /> select day, cumulative - nvl(lag(cumulative,1) over (order by day), 0) as total_for_the_day <br /> from silly;<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />PLAN_TABLE_OUTPUT<br />---------------------------------------------<br />Plan hash value: 3997035406<br />----------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />----------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 4 | 104 | 3 (34)| 00:00:01 |<br />| 1 | WINDOW SORT | | 4 | 104 | 3 (34)| 00:00:01 |<br />| 2 | TABLE ACCESS FULL| SILLY | 4 | 104 | 2 (0)| 00:00:01 |<br />----------------------------------------------------------------------------<br />
    97. 97. Tip4 : Use Analytic Functions if Possible<br />SQL&gt; select day, cumulative as total_for_the_day from silly where rownum =1 union all<br /> select t2.day, t2.cumulative - t1.cumulative as Total_For_the_Day from silly t1, silly t2 where t1.day = t2.day-1;<br /> DAY TOTAL_FOR_THE_DAY<br />---------- -----------------<br /> 1 5<br /> 2 5<br /> 3 5<br /> 4 5<br />Elapsed: 00:00:00.02<br />SQL&gt; select day, cumulative - nvl(lag(cumulative,1) over (order by day), 0) as total_for_the_day from silly;<br /> DAY TOTAL_FOR_THE_DAY<br />---------- -----------------<br /> 1 5<br /> 2 5<br /> 3 5<br /> 4 5<br />Elapsed: 00:00:00.00<br />
    98. 98. Tip4 : Use Analytic Functions if Possible<br />select mod(member_id,1000) , <br /> count(*) OVER<br /> (PARTITION BY mod(member_id,1000))<br />from verybigTable <br />where (mod(member_id,1000) between 700 and 749 or mod(member_id,1000) between 600 and 649 or mod(member_id,1000) between 700 and 749)<br /> and page_key = ’key1’<br />Execution time ~ 13mins<br />select 1 as id, count(1)<br />from verybigTable<br />where mod(member_id,1000) between 700 and 749<br />and key = ’key1&apos;<br />union all<br />select 2 as id, count(1)<br />from verybigTable<br />where mod(member_id,1000) between 600 and 649<br />and key = ’key1&apos;<br />union all<br />select 3 as id, count(1)<br />from verybigTable<br />where mod(member_id,1000) between 700 and 749<br />and page_key = ’key1’<br />Execution time ~ 3hrs<br />
    99. 99. Tip5 : Do not Use Views Blindly <br />“How many histogram buckets obj$ has?”<br />SQL&gt; explain plan for select count(*) from dba_histograms where table_name = &apos;OBJ$&apos;;<br />Explained.<br />
    100. 100. Tip5 : Do not Use Views Blindly <br />SQL&gt; explain plan for select count(*) from obj$ o, histgrm$ h where o.obj# = h.obj# and o.name = &apos;OBJ$&apos;;<br />Explained.<br />SQL&gt; @?/rdbms/admin/utlxpls<br />-----------------------------------------------------------------------------------------------<br />| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |<br />-----------------------------------------------------------------------------------------------<br />| 0 | SELECT STATEMENT | | 1 | 34 | 31 (0)| 00:00:01 |<br />| 1 | SORT AGGREGATE | | 1 | 34 | | |<br />| 2 | NESTED LOOPS | | 198 | 6732 | 31 (0)| 00:00:01 |<br />| 3 | TABLE ACCESS BY INDEX ROWID| OBJ$ | 2 | 60 | 29 (0)| 00:00:01 |<br />|* 4 | INDEX SKIP SCAN | I_OBJ2 | 2 | | 27 (0)| 00:00:01 |<br />|* 5 | INDEX RANGE SCAN | I_H_OBJ#_COL# | 104 | 416 | 1 (0)| 00:00:01 |<br />-----------------------------------------------------------------------------------------------<br />Predicate Information (identified by operation id):<br />---------------------------------------------------<br /> 4 - access(&quot;O&quot;.&quot;NAME&quot;=&apos;OBJ$&apos;)<br /> filter(&quot;O&quot;.&quot;NAME&quot;=&apos;OBJ$&apos;)<br /> 5 - access(&quot;O&quot;.&quot;OBJ#&quot;=&quot;H&quot;.&quot;OBJ#&quot;)<br />19 rows selected.<br />
    101. 101. Tip5 : Do not Use Views Blindly <br />
    102. 102. Tip6: Wildcards are bad<br />Select * from schools where school_name like ‘abc%’ <br />Select * from schools where school_name like ‘%abc%’<br />Select * from schools where school_name like ‘%abc’<br /><ul><li>Optimizer estimations are very bad for the last two
    103. 103. Try not to use wildcards</li></li></ul><li>Tip7: Use semi-joins and anti-joins<br /><ul><li>A list of departments with at least one employee</li></ul>SELECT D.deptno, D.dname<br />FROM dept D, emp E <br />WHERE E.deptno = D.deptno<br />ORDER BY D.deptno;<br />SELECT D.deptno, D.dname<br /> FROM dept D <br /> WHERE EXISTS ( SELECT 1 FROM emp E <br /> WHERE E.deptno = D.deptno ) <br />ORDER BY D.deptno;<br />
    104. 104. More tips<br />code the query as simply as possible <br />no unnecessary columns are selected, no unnecessary GROUP BY or ORDER BY<br />Do not use SELECT * FROM …… if not needed<br />Do not use functions in the where clause<br />Use WHERE SALES &lt; 1000/(1 + n) instead of
WHERE SALES + (n * SALES) &lt; 1000;<br />Avoid a HAVING clause in SELECT statements<br />A WHERE clause may be more efficient<br />
    105. 105. Q/A<br />Thank you ! <br />

    ×