Your SlideShare is downloading. ×
SQL Performance Solutions: Refactor Mercilessly, Index Wisely
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

SQL Performance Solutions: Refactor Mercilessly, Index Wisely

417
views

Published on

Published in: Technology

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

  • Be the first to like this

No Downloads
Views
Total Views
417
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Refactor  Mercilessly,   Index  Wisely   Karen  Morton   Sr.  Technical  Consultant  
  • 2. karen.morton@enkitec.com  karenmorton.blogspot.com  karen_morton  
  • 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. RewriHng   SQL  
  • 5. First   things   first  (This  stuff  is  really  important)  
  • 6. Review  the  statement.    
  • 7. What  is  it            supposed                      to  do?    
  • 8. Collect  data.    
  • 9. Review  staHsHcs.    
  • 10. Check   indexes     and                  constraints.  
  • 11. Execute  the  query.  
  • 12. Evaluate   the  plan.  (compare  esHmates  to  actuals)  
  • 13. Where  are  the    big  hiFers?   Time?   Resources?  
  • 14. Refactor  the  statement.   (if  you  should)  
  • 15. Modify  or  Add  indexes,  constraints,  staHsHcs.   (if  you  should)  
  • 16. T  T  D  (Test  To  DestrucHon)  
  • 17. Iterate   unHl  target  met  or  no  further  improvement  possible  
  • 18. How  do  you  do  simple,    yet  effecHve,  tesHng?  
  • 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. /*+  gather_plan_staHsHcs  */   (staHsHcs_level  =  ALL)  
  • 21. dbms_xplan.display_cursor   (ALLSTATS  LAST)  
  • 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. /*+  monitor  */  
  • 24. dbms_sqltune.report_sql_monitor   (TEXT,  HTML,  XML,  ACTIVE)   Monitored  statements  can  be  found  in  V$SQL_MONITOR  
  • 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. @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. @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. How  do  you  know  when   refactoring  SQL  is  the   best  opHon?  
  • 29. A  poor  execuHon  plan   is  consistently     developed.  
  • 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. Common  Refactoring     SituaHons  
  • 32. Look  for    "column-­‐less"  joined  tables.  
  • 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. Look  for     improper  outer  joins.  
  • 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. Look  for     repeated  use  of  same  tables  and  predicates.  
  • 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. Look  for     simple  predicates   ORed  with  other  predicates  in  ranges.  
  • 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. Look  for   DISTINCT/UNION  to  remove  duplicates.   Consider  using  IN  or  EXISTS  instead.  
  • 41. Think  like  the  opHmizer.   Query  TransformaHon  
  • 42. Simple  View  Merging   is transformed intoMerged  automaHcally  as  it  is  deemed  “always  beFer”     for  the  opHmizer  to  work  with  direct  joins.  
  • 43. Complex  View  Merging   is transformed into “Complex”  due  to  GROUP  BY.    CVM  can  also  be  done  when  using  DISTINCT  or  outer  join.  
  • 44. Filter  Push-­‐Down   is transformed intoPurpose:  To  push  outer  query  predicates  into  view  to  perform  earlier  filtering.  
  • 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. 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. Understanding  how  the   opHmizer  transforms  queries  helps  you  write  beFer  SQL  and   understand  execuHon  plans.  
  • 48. How  and  When   to  Index  
  • 49. For  many  years,  inadequate  indexing  has  been  the  most    common  cause  of  performance  disappointments.     –    Tapio  Lahdenmäki    
  • 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. How  many  is  "too"  many?  
  • 52. Heavy  DML?  Large,  bulk  loads?   or   Mostly  query?  
  • 53. Indexes  support  query  performance  
  • 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. Note  the  number  of  rows  that  are  thrown  away  in  step  1  (79).  
  • 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. 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. 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. A  3-­‐star  index  is   oten  called  a   fat   index.    
  • 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. There  will  always  be  trade-­‐offs.     Test  alternaHves  or  use   "worst  case"  formula  to   esHmate  response  Hmes.      
  • 62. The  key  to  determining  an  ideal  index       The  index  should  provide   adequate  enough  screening   to  minimize  table  accesses.      
  • 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. Q  &  A  
  • 65. Thank  you!  

×