Successfully reported this slideshow.
Refactor	  Mercilessly,	      Index	  Wisely	            Karen	  Morton	    Sr.	  Technical	  Consultant	  
karen.morton@enkitec.com	  karenmorton.blogspot.com	  karen_morton	  
Topics	  •  Common	  ways	  to	  rewrite	  SQL	  to	  make	  it	     perform	  beFer	  and	  more	  consistently	  •  How	...
RewriHng	    SQL	  
First	                  things	                   first	  (This	  stuff	  is	  really	  important)	  
Review	  the	  statement.	  	  
What	  is	  it	  	         	   	   	   	  supposed	  	         	   	   	   	   	   	   	   	   	  to	  do?	  	  
Collect	  data.	         	  
Review	  staHsHcs.	              	  
Check	              indexes	  	                     and	  	  	  	   	  	   	  	   	  constraints.	  
Execute	  the	  query.	  
Evaluate	              the	  plan.	  (compare	  esHmates	  to	  actuals)	  
Where	  are	  the	  	  big	  hiFers?	         Time?	     Resources?	  
Refactor	  the	  statement.	     (if	  you	  should)	  
Modify	  or	  Add	  indexes,	  constraints,	  staHsHcs.	               (if	  you	  should)	  
T	  T	  D	  (Test	  To	  DestrucHon)	  
Iterate	      unHl	  target	  met	  or	  no	  further	  improvement	  possible	  
How	  do	  you	  do	  simple,	  	  yet	  effecHve,	  tesHng?	  
Name	  your	  SQL	                        SELECT /* kmtest */ …                      FROM   tab …                      SEL...
/*+	  gather_plan_staHsHcs	  */	         (staHsHcs_level	  =	  ALL)	  
dbms_xplan.display_cursor	         (ALLSTATS	  LAST)	  
SQL> select          /* kmtest */          /*+ gather_plan_statistics */          count(*)     from sales ;Plan hash value...
/*+	  monitor	  */	  
dbms_sqltune.report_sql_monitor	        (TEXT,	  HTML,	  XML,	  ACTIVE)	         Monitored	  statements	  can	  be	  found...
SQL> select          /* sql42 */          /*+ monitor */          count(*)     from sales ;Global Stats===================...
@fsx kmtest!!!col sql_id       new_value r_sqlid!col child_number new_value r_childno!!!SELECT /* NOVIEW */ !  ! ! sql_id,...
@dplan!SELECT *!FROM    table(dbms_xplan.display_cursor (! ! ! SQL_ID => &r_sqlid, ! ! ! CURSOR_CHILD_NO => NVL(&r_childno...
How	  do	  you	  know	  when	   refactoring	  SQL	  is	  the	        best	  opHon?	  
A	  poor	  execuHon	  plan	         is	  consistently	  	           developed.	  
Why	  You	  Should	  Refactor	  •    You	  know	  your	  stuff	  best	  (or	  you	  should)	  •    Always	  filter	  early	 ...
Common	  Refactoring	  	      SituaHons	  
Look	  for	  	  "column-­‐less"	  joined	  tables.	  
This	   SELECT       b.* FROM         a, b WHERE        a.col1 = b.col1 AND          b.col2 = <condition>Becomes	   SELECT...
Look	  for	  	   improper	  outer	  joins.	  
This	   AND tab1.col1 = tab2.col1 (+) AND tab2.col2 = <condition>Becomes	   AND tab1.col1 = tab2.col1 AND tab2.col2 = <con...
Look	  for	  	   repeated	  use	  of	  same	  tables	  and	  predicates.	  
SELECT rite.event_name, count(*)  FROM riffs.rf_order ro, riffs.rf_order_item roi,       riffs.rf_item_transaction rit,   ...
Look	  for	  	   simple	  predicates	    ORed	  with	  other	  predicates	  in	  ranges.	  
This	               col1 > <condition> OR          col2 > <condition>Becomes	       col1 > <condition> UNION / UNION ALL A...
Look	  for	     DISTINCT/UNION	  to	  remove	  duplicates.	      Consider	  using	  IN	  or	  EXISTS	  instead.	  
Think	  like	  the	  opHmizer.	   Query	  TransformaHon	  
Simple	  View	  Merging	                          is transformed intoMerged	  automaHcally	  as	  it	  is	  deemed	  “alwa...
Complex	  View	  Merging	                           is transformed into                      “Complex”	  due	  to	  GROUP	...
Filter	  Push-­‐Down	                                         is transformed intoPurpose:	  To	  push	  outer	  query	  pr...
Predicate	  Move-­‐Around	                                          is transformed intoPurpose:	  To	  move	  inexpensive	...
Join	  FactorizaHon	                                           is transformed intoCombines	  branches	  of	  UNION	  /	  U...
Understanding	  how	  the	   opHmizer	  transforms	  queries	  helps	  you	  write	  beFer	  SQL	  and	   understand	  exe...
How	  and	  When	    to	  Index	  
For	  many	  years,	  inadequate	  indexing	  has	  been	  the	  most	  	  common	  cause	  of	  performance	  disappointm...
Indexing	  Problems	  •  Indexes	  that	  do	  not	  have	  sufficient	  columns	  to	     support	  all	  predicates	  •  N...
How	  many	  is	  "too"	  many?	  
Heavy	  DML?	  Large,	  bulk	  loads?	             or	    Mostly	  query?	  
Indexes	  support	  query	  performance	  
Inadequate	  Index	  SELECT !cust_id, cust_first_name!FROM ! !customers!    !WHERE ! !cust_last_name = Ruddy!AND ! ! !cust...
Note	  the	  number	  of	  rows	  that	  are	  thrown	  away	  in	  step	  1	  (79).	  
Index	  on	  CUST_LAST_NAME,	  CUST_CITY	                                   No	  throwaway	  Index	  on	  CUST_CITY,	  CUS...
Index	  Design	  Strategies	  Columns	  from	  all	  equality	  predicates	  in	  any	  order	  	  Add	  columns	  in	  th...
Range	  predicates	               are	  usually	  placed	  ater	                1	  and	  2	  star	  columns.	            ...
A	  3-­‐star	  index	  is	   oten	  called	  a	             fat             	            index.	  	  
An	  index	  that	  contains	  all	  the	        columns	  referenced	  in	         the	  WHERE	  clause	  is	  a	  	     ...
There	  will	  always	  be	  trade-­‐offs.	                       	     Test	  alternaHves	  or	  use	     "worst	  case"	 ...
The	  key	  to	  determining	  an	  ideal	  index	  	  	                The	  index	  should	  provide	               adeq...
Recap	  •  Look	  for	  common	  anH-­‐paFerns	  in	  SQL	  •  Gather	  enough	  diagnosHc	  data	  to	  know	  where	    ...
Q	  &	  A	  
Thank	  you!	  
SQL Performance Solutions: Refactor Mercilessly, Index Wisely
Upcoming SlideShare
Loading in …5
×

SQL Performance Solutions: Refactor Mercilessly, Index Wisely

790 views

Published on

Published in: Technology
  • Be the first to comment

SQL Performance Solutions: Refactor Mercilessly, Index Wisely

  1. 1. Refactor  Mercilessly,   Index  Wisely   Karen  Morton   Sr.  Technical  Consultant  
  2. 2. karen.morton@enkitec.com  karenmorton.blogspot.com  karen_morton  
  3. 3. Topics  •  Common  ways  to  rewrite  SQL  to  make  it   perform  beFer  and  more  consistently  •  How  to  easily  idenHfy  &  test  your  SQL  •  How  and  when  to  index   –  AddiHons  or  modificaHons  to  provide  best  soluHon   –  Best  choice  of  columns  and  in  what  order   –  Trade-­‐offs  for  determining  the  "best"  index  
  4. 4. RewriHng   SQL  
  5. 5. First   things   first  (This  stuff  is  really  important)  
  6. 6. Review  the  statement.    
  7. 7. What  is  it            supposed                      to  do?    
  8. 8. Collect  data.    
  9. 9. Review  staHsHcs.    
  10. 10. Check   indexes     and                  constraints.  
  11. 11. Execute  the  query.  
  12. 12. Evaluate   the  plan.  (compare  esHmates  to  actuals)  
  13. 13. Where  are  the    big  hiFers?   Time?   Resources?  
  14. 14. Refactor  the  statement.   (if  you  should)  
  15. 15. Modify  or  Add  indexes,  constraints,  staHsHcs.   (if  you  should)  
  16. 16. T  T  D  (Test  To  DestrucHon)  
  17. 17. Iterate   unHl  target  met  or  no  further  improvement  possible  
  18. 18. How  do  you  do  simple,    yet  effecHve,  tesHng?  
  19. 19. Name  your  SQL   SELECT /* kmtest */ … FROM tab … SELECT /*+ qb_name (sql42) */ … FROM tab …Comments  stored  with  full  SQL  in  the  SQL_TEXT  column  in  v$sql,  v$sqltext,  dba_hist_sqltext.     QBLOCK_NAME  stored  in  v$sql_plan,  v$sql_plan_staHsHcs_all,  dba_hist_sql_plan.  
  20. 20. /*+  gather_plan_staHsHcs  */   (staHsHcs_level  =  ALL)  
  21. 21. dbms_xplan.display_cursor   (ALLSTATS  LAST)  
  22. 22. SQL> select /* kmtest */ /*+ gather_plan_statistics */ count(*) from sales ;Plan hash value: 1047182207----------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.13 | 4440 || 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.13 | 4440 || 2 | TABLE ACCESS STORAGE FULL| SALES | 1 | 918K| 918K|00:00:00.08 | 4440 |----------------------------------------------------------------------------------------------
  23. 23. /*+  monitor  */  
  24. 24. dbms_sqltune.report_sql_monitor   (TEXT,  HTML,  XML,  ACTIVE)   Monitored  statements  can  be  found  in  V$SQL_MONITOR  
  25. 25. SQL> select /* sql42 */ /*+ monitor */ count(*) from sales ;Global Stats=================================================| Elapsed | Cpu | Other | Fetch | Buffer || Time(s) | Time(s) | Waits(s) | Calls | Gets |=================================================| 0.03 | 0.03 | 0.00 | 1 | 4440 |=================================================SQL Plan Monitoring Details (Plan Hash Value=1047182207)======================================================================================================| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows || | | | (Estim) | | Active(s) | Active | | (Actual) |======================================================================================================| 0 | SELECT STATEMENT | | | | 1 | +0 | 1 | 1 || 1 | SORT AGGREGATE | | 1 | | 1 | +0 | 1 | 1 || 2 | TABLE ACCESS STORAGE FULL | SALES | 919K | 1230 | 1 | +0 | 1 | 919K |======================================================================================================
  26. 26. @fsx kmtest!!!col sql_id new_value r_sqlid!col child_number new_value r_childno!!!SELECT /* NOVIEW */ ! ! ! sql_id, child_number ...!FROM gv$sql s!WHERE sql_text like %&&1%!AND sql_text not like %NOVIEW%!AND sql_text not like BEGIN :sql_%!ORDER BY 1 ;!
  27. 27. @dplan!SELECT *!FROM table(dbms_xplan.display_cursor (! ! ! SQL_ID => &r_sqlid, ! ! ! CURSOR_CHILD_NO => NVL(&r_childno,0), ! ! ! FORMAT => ALLSTATS LAST)) !WHERE &r_sqlid IS NOT NULL ;!@rsm!SELECT dbms_sqltune.report_sql_monitor(! ! ! SQL_ID => &r_sqlid,! ! ! TYPE => HTML) !FROM dual!WHERE &r_sqlid IS NOT NULL ;!
  28. 28. How  do  you  know  when   refactoring  SQL  is  the   best  opHon?  
  29. 29. A  poor  execuHon  plan   is  consistently     developed.  
  30. 30. Why  You  Should  Refactor  •  You  know  your  stuff  best  (or  you  should)  •  Always  filter  early  •  Defines  your  expectaHons  •  K.I.S.S.  •  The  opHmizer  might  not  be  able  to  
  31. 31. Common  Refactoring     SituaHons  
  32. 32. Look  for    "column-­‐less"  joined  tables.  
  33. 33. This   SELECT b.* FROM a, b WHERE a.col1 = b.col1 AND b.col2 = <condition>Becomes   SELECT b.* FROM b WHERE b.col2 = <condition> AND EXISTS (SELECT null FROM a WHERE a.col1 = b.col1)
  34. 34. Look  for     improper  outer  joins.  
  35. 35. This   AND tab1.col1 = tab2.col1 (+) AND tab2.col2 = <condition>Becomes   AND tab1.col1 = tab2.col1 AND tab2.col2 = <condition>Because  the  condiHon  would  be  null  for  the  outer  joined  row,    so  the  predicate  could  never  be  true.  
  36. 36. Look  for     repeated  use  of  same  tables  and  predicates.  
  37. 37. SELECT rite.event_name, count(*) FROM riffs.rf_order ro, riffs.rf_order_item roi, riffs.rf_item_transaction rit, riffs.rf_item_transaction_event rite WHERE ro.is_test = 0 AND ro.order_id = roi.order_id AND roi.order_item_id = rit.order_item_id AND roi.order_id = rit.order_id AND rit.transaction_id = rite.transaction_id AND (rite.event_name >AUTHORIZED OR rite.event_name <AUTHORIZED) GROUP BY rite.event_nameUNION ALLSELECT TRANSACTION_INITIATED, count(*) FROM(SELECT count(*) FROM riffs.rf_order ro, riffs.rf_order_item roi, riffs.rf_item_transaction rit, riffs.rf_item_transaction_event rite WHERE ro.is_test = 0 AND ro.order_id = roi.order_id AND roi.order_item_id = rit.order_item_id AND roi.order_id = rit.order_id AND rit.transaction_id = rite.transaction_id AND rite.event_name = AUTHORIZED GROUP BY substr(rit.TRANSACTION_ID,1,INSTR(rit.TRANSACTION_ID,_)-1))
  38. 38. Look  for     simple  predicates   ORed  with  other  predicates  in  ranges.  
  39. 39. This   col1 > <condition> OR col2 > <condition>Becomes   col1 > <condition> UNION / UNION ALL AND col2 > <condition>Because  a  row  could  not  be  rejected  when  one  predicate  is  false  without  checking  the  other  predicates.  
  40. 40. Look  for   DISTINCT/UNION  to  remove  duplicates.   Consider  using  IN  or  EXISTS  instead.  
  41. 41. Think  like  the  opHmizer.   Query  TransformaHon  
  42. 42. Simple  View  Merging   is transformed intoMerged  automaHcally  as  it  is  deemed  “always  beFer”     for  the  opHmizer  to  work  with  direct  joins.  
  43. 43. Complex  View  Merging   is transformed into “Complex”  due  to  GROUP  BY.    CVM  can  also  be  done  when  using  DISTINCT  or  outer  join.  
  44. 44. Filter  Push-­‐Down   is transformed intoPurpose:  To  push  outer  query  predicates  into  view  to  perform  earlier  filtering.  
  45. 45. Predicate  Move-­‐Around   is transformed intoPurpose:  To  move  inexpensive  predicates  into  view  query  blocks  to  perform  earlier  filtering.   Can  generate  filter  predicates  based  on  transiHvity  or  funcHonal  dependencies.  
  46. 46. Join  FactorizaHon   is transformed intoCombines  branches  of  UNION  /  UNION  ALL  that  join  a  common  table  in  order  to   reduce  #  of  accesses  to  that  table.  
  47. 47. Understanding  how  the   opHmizer  transforms  queries  helps  you  write  beFer  SQL  and   understand  execuHon  plans.  
  48. 48. How  and  When   to  Index  
  49. 49. For  many  years,  inadequate  indexing  has  been  the  most    common  cause  of  performance  disappointments.     –    Tapio  Lahdenmäki    
  50. 50. Indexing  Problems  •  Indexes  that  do  not  have  sufficient  columns  to   support  all  predicates  •  Not  enough  indexes  present   –  Numerous  single-­‐column  but  few  mulH-­‐column  •  Indexes  with  the  right  columns  but  in  the   wrong  order  
  51. 51. How  many  is  "too"  many?  
  52. 52. Heavy  DML?  Large,  bulk  loads?   or   Mostly  query?  
  53. 53. Indexes  support  query  performance  
  54. 54. Inadequate  Index  SELECT !cust_id, cust_first_name!FROM ! !customers! !WHERE ! !cust_last_name = Ruddy!AND ! ! !cust_city = Ede!ORDER BY cust_first_name ;! Index  present  on  CUST_LAST_NAME,  CUST_FIRST_NAME   #  rows  in  table  =  55,500  
  55. 55. Note  the  number  of  rows  that  are  thrown  away  in  step  1  (79).  
  56. 56. Index  on  CUST_LAST_NAME,  CUST_CITY   No  throwaway  Index  on  CUST_CITY,  CUST_LAST_NAME,  CUST_FIRST_NAME,  CUST_ID   No  throwaway,  no  sort  
  57. 57. Index  Design  Strategies  Columns  from  all  equality  predicates  in  any  order    Add  columns  in  the  order  used  in  ORDER  BY    Add  all  remaining  columns  from  column  list  in  any  order  •  VolaHle  columns  at  end  (reduces  impact  on   updates)  
  58. 58. Range  predicates   are  usually  placed  ater   1  and  2  star  columns.   Range  predicates  mean  3-­‐star  indexes  arent  possible.  The  2nd  star  is  usually  sacrificed  in  preference  of  a  more  selecHve  index.  
  59. 59. A  3-­‐star  index  is   oten  called  a   fat   index.    
  60. 60. An  index  that  contains  all  the   columns  referenced  in   the  WHERE  clause  is  a     semi-fat   index.     If  no  semi-­‐fat  index  exists,  this  is  a  warning  flag   for  possible  performance  issues.  
  61. 61. There  will  always  be  trade-­‐offs.     Test  alternaHves  or  use   "worst  case"  formula  to   esHmate  response  Hmes.      
  62. 62. The  key  to  determining  an  ideal  index       The  index  should  provide   adequate  enough  screening   to  minimize  table  accesses.      
  63. 63. Recap  •  Look  for  common  anH-­‐paFerns  in  SQL  •  Gather  enough  diagnosHc  data  to  know  where   the  problem  originates  •  Learn  what  the  opHmizer  expects  (and  give  it   what  it  wants!)  •  Think  about  your  indexing  strategy  •  Design  indexes  for  opHmal  coverage  to  limit   table  accesses      
  64. 64. Q  &  A  
  65. 65. Thank  you!  

×