SQL Tuning and VST
Upcoming SlideShare
Loading in...5
×
 

SQL Tuning and VST

on

  • 1,254 views

Methodology to find a candidate for the optimal execution plan of a SQL query

Methodology to find a candidate for the optimal execution plan of a SQL query

Statistics

Views

Total Views
1,254
Views on SlideShare
1,252
Embed Views
2

Actions

Likes
0
Downloads
49
Comments
0

1 Embed 2

https://twitter.com 2

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Layout a diagram tables as nodes and joins as connectorsDraw connectors for each join in where clause1 to 1 connectionuse blue line1 to many  use black linecrows feet towards manymany to many crows feet on both endsCalculate filter ratios for any tables with filtersfilter ratio = number of rows returned with filter / number of rowsdisplay in yellow below table nodeFind the table sizes for each tabledisplay in green above table nodeCalculate two table join sizes for all two table joins in diagram (ie for every connection line)extract the join information, including filters, and run count on that joindisplay in red on join lineAlternatively, or as a complement, calculate join filter ratios in both directionsdisplay at each end of join connection line
  • SELECT order_line_dataFROM customers cus INNER JOIN orders ord ON ord.id_customer = cus.id INNER JOIN order_linesorl ON orl.id_order = ord.id INNER JOIN products prd1 ON prd1.id = orl.id_product INNER JOIN suppliers sup1 ON sup1.id = prd1.id_supplierWHERE cus.location = 'LONDON' AND ord.date_placed BETWEEN '04-JUN-10' AND '11-JUN-10' AND sup1.location = 'LEEDS' AND EXISTS ( SELECT NULL FROM alternatives alt INNER JOIN products prd2 ON prd2.id = alt.id_product_sub INNER JOIN suppliers sup2 ON sup2.id = prd2.id_supplier WHERE alt.id_product = prd1.id AND sup2.location != 'LEEDS' )

SQL Tuning and VST SQL Tuning and VST Presentation Transcript

  • Visual SQL Tuning (VST)Kyle Haileyhttp://dboptimizer.com
  • SQL TuningMethodology1. Find: Problem SQL2. Study: SQL Execution Plan3. Fix: How ?
  • Step 1 : Find “bad” SQL1. Users complain2. High Resources3. Monitoring
  • Step 2: Get Explain Plan--------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows |---------------------------------------------------------------------------------------------| 1 | HASH GROUP BY | | 1 | 1 | 1 ||* 2 | FILTER | | 1 | | 1909 ||* 3 | TABLE ACCESS BY INDEX ROWID | PS_RETROPAYPGM_TBL | 1 | 1 | 3413 || 4 | NESTED LOOPS | | 1 | 165 | 6827 ||* 5 | HASH JOIN | | 1 | 165 | 3413 ||* 6 | HASH JOIN | | 1 | 165 | 3624 || 7 | TABLE ACCESS BY INDEX ROWID | WB_JOB | 1 | 242 | 2895 || 8 | NESTED LOOPS | | 1 | 233 | 2897 || 9 | TABLE ACCESS BY INDEX ROWID| PS_PAY_CALENDAR | 1 | 1 | 1 ||* 10 | INDEX RANGE SCAN | PS0PAY_CALENDAR | 1 | 1 | 1 ||* 11 | INDEX RANGE SCAN | WBBJOB_B | 1 | 286 | 2895 ||* 12 | TABLE ACCESS FULL | WB_RETROPAY_EARNS | 1 | 27456 | 122K|| 13 | TABLE ACCESS FULL | PS_RETROPAY_RQST | 1 | 13679 | 13679 ||* 14 | INDEX RANGE SCAN | PS#RETROPAYPGM_TBL | 3413 | 1 | 3413 || 15 | SORT AGGREGATE | | 1791 | 1 | 1791 || 16 | FIRST ROW | | 1791 | 1 | 1579 ||* 17 | INDEX RANGE SCAN (MIN/MAX) | WB_JOB_F | 1791 | 1 | 1579 || 18 | SORT AGGREGATE | | 1539 | 1 | 1539 || 19 | FIRST ROW | | 1539 | 1 | 1539 ||* 20 | INDEX RANGE SCAN (MIN/MAX) | WB_JOB_G | 1539 | 1 | 1539 |---------------------------------------------------------------------------------------------Predicate Information (identified by operation id):---------------------------------------------------2 - filter(("B"."EFFDT"= AND "B"."EFFSEQ"=))3 - filter("E"."OFF_CYCLE"="A"."PAY_OFF_CYCLE_CAL")5 - access("D"."RETROPAY_SEQ_NO"="C"."RETROPAY_SEQ_NO")6 - access("C"."EMPLID"="B"."EMPLID" AND "C"."EMPL_RCD#"="B"."EMPL_RCD#")10 - access("A"."RUN_ID"=PD2 AND "A"."PAY_CONFIRM_RUN"=N)11 - access("B"."COMPANY"="A"."COMPANY" AND "B"."PAYGROUP"="A"."PAYGROUP")12 - filter(("C"."RETROPAY_PRCS_FLAG"=C AND "C"."RETROPAY_LOAD_SW"=Y))14 - access("E"."RETROPAY_PGM_ID"="D"."RETROPAY_PGM_ID")17 - access("F"."EMPLID"=:B1 AND "F"."EMPL_RCD#"=:B2 AND "F"."EFFDT"<=:B3)20 - access("G"."EMPLID"=:B1 AND "G"."EMPL_RCD#"=:B2 AND "G"."EFFDT"=:B3)PARSING IN CURSOR #2 len=53 dep=0 uid=61 oct=3lid=61 tim=1151519905950403 hv=2296704914ad=4e50010cSELECT Hello, world; today is || SYSDATE FROM dualEND OF STMTPARSE#2:c=4000,e=1540,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=1151519905950397BINDS #2:EXEC#2:c=0,e=58,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1151519906034782WAIT #2: nam=SQL*Net message to client ela= 2 driverid=1650815232 #bytes=1 p3=0 obj#=-1tim=1151519906034809FETCH#2:c=0,e=29,p=0,cr=0,cu=0,mis=0,r=1,dep=0,og=1,tim=1151519906034864WAIT #2: nam=SQL*Net message from client ela= 215driver id=1650815232 #bytes=1 p3=0 obj#=-1tim=1151519906035133FETCH#2:c=0,e=1,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=1151519906035165WAIT #2: nam=SQL*Net message to client ela= 1 driverid=1650815232 #bytes=1 p3=0 obj#=-1tim=1151519906035188WAIT #2: nam=SQL*Net message from client ela= 192driver id=1650815232 #bytes=1 p3=0 obj#=-1tim=1151519906035400STAT #2 id=1 cnt=1 pid=0 pos=1 obj=0 op=FASTDUAL (cr=0 pr=0 pw=0 time=3 us)Trace fie
  • Step 3: ???Methodology• Identify Slow Queries• Look at Execution Plan• FixFix1. Analyze stats2. Go to step 1WTF??Fix If you are lucky, analyze for1. Column histograms2. Missing or better Indexes
  • Explain Plan: Like DirectionsWhere is the Map?
  • Explain Plan: Like DirectionsWhere is the Map?
  • Explain Plan: Like DirectionsWhere is the Map?
  • SQL Tuning1. Two Table Join2. Multi-Table Join3. Create Map4. Design Methodology5. Examples
  • How to Join two tables?1. Which table to start with• Hardest step ?2. What Indexes to use3. What type of join to use HJ, NLDesign options:• Partitions• IOT• Bitmap indexes• Hash cluster• Materialized views• etc
  • Two Table Join1. Index exist?2. Type of Relation• One to One• One to Many• Many to Many3. Special Cases• Outer Joins• Not Exists
  • Table Join Orderselect *from a, bwherea.id = b.idA Bid dataid dataEvery row visits Every rowWork= A-rows x B-rows (8 x 4 )HJ would optimizes to simulate index lookupIf No Index then (NL) order doesn’t matter
  • 2 Table join, with indexesselect *from a, bwherea.id = b.idA Bid datadata idWith IndexesStart with the least rows8
  • 2 Table join, with indexesselect *from a, bwherea.id = b.idA Bid datadata idWith IndexesStart with the least rowsB Adata id id data8 4
  • 2 table join - filtersselect *from a, bwherea.id = b.id -- joinand a.field = ‘val a’ -- filter aand b.field = ‘val b’ -- filter bABid datadata idStart on table with least rows after filter23
  • Two Table Joins – looks simpleA BInner Join
  • Two Table JoinsA BA BA BLeft join B B(+)Not exists BInner Join
  • Two Table JoinsA BA BA BA BA BLeft join B B(+)Not exists BRight join B A(+)Not Exists AInner Join
  • Two Table JoinsA BA BA BA B A BA BA BLeft join B B(+)Not exists BFull outer (union) Right join B A(+)Not Exists AUnion of Not ExistsInner JoinDoesn’t tell the wholestoryMissing « amplifications »
  • One to One - intersection12121 12 2A BA BBAMAP
  • One to Many - projection1122121 11 12 22 2BAA BA BMAP
  • 111111Many to Many - amplification1 11 11 11 11 11 11 11 1A BABA BMAPrA*rB-------------------------min(ndv(A),ndv(B))
  • Two Table JoinsA B A BLeft join B B(+) Right join B A(+)A BMAP MAPA Bo o
  • Two Table JoinsA BLeft join B B(+)Color nodes that return no dataSelect a.* from a, b where b.field(+) = a.field;A BVA BVMultiplieroo ?oPointless – join onB has no affect ifno B cols selectedVPointless – join onB has no affect ormultiplies rows fromA if no B colsselected
  • ExistsSELECT *FROM dept d WHERE exists ( SELECT null FROMemp e WHERE e.deptno=d.deptno);SELECT *FROM dept d WHERE d.deptno in( SELECT deptno FROM emp e );Select dept.* from emp, dept where emp.deptno=dept.deptno; /* can get duplicates */dept empEMAP
  • Not ExistsSELECT *FROM dept d WHERE not exists ( SELECTnull FROM emp e WHERE e.deptno=d.deptno);SELECT *FROM dept d WHERE d.deptno not in ( SELECTdeptno FROM emp e and deptno is not null );SELECT dept.* FROM dept LEFT OUTER JOIN empON dept.deptno = emp.deptno WHERE emp.deptno ISNULL;dept empNMAP
  • Two Table Join1. Where to start1. Generally start with the least rows after filtering withpredicate2. Drawing Map:– One to One / One to Many / Many to Many– Outer Joins / Not ExistsNow , three table joins:A BNA BoBA A B A B
  • Three table join1 row4 rows8 rowsEx) 1 customer 4 orders, each order has 2 order_lines each1 row1 row1 roworder_lines orders customerJoin directionJoin direction
  • Three table joinorder_lines orders customerFWhereorder_lines.field = valueA Filter on order_lines is going to eliminate workon orders and customers, if we start at order_lines
  • Three table joinorder_lines orders customerFWhereorder_lines.field = valueStarting with a filter on order_lines is going to eliminate work
  • Three table joinorder_lines orders customerFWhereorders.field = valueStarting with a Filter on orders is going to eliminate workThen Join to customers => keeps the number of rows the same12
  • Three table joinorder_lines orders customerFWherecustomer.field = valueStarting on a filter on customer is going to eliminate work
  • Three table joinorder_lines orders customerFFFWhat if a filter on all three?Choose the one that filter’s the highestpercent of the table.100% * (select count(*) from TAB where condition)---------------------------(select count(*) from Tab)
  • 4 or more table joinOracle can only join one table in at a time.Oracle can’t (normally) join two different sub-branches
  • Put it all together : VST1. Tables– drawn as nodes2. Joins :– drawn map connector lines• One-to-one, one-to-many, many-to-many• Exists, not exists, outer joins3. Filters– mark on each table with filter in where clause35 6/22/2013
  • How to VST: Tables and JoinsSELECT C.Phone_Number, C.Honorific, C.First_Name, C.Last_Name,C.Suffix, C.Address_ID, A.Address_ID, A.Street_Address_Line1,A.Street_Address_Line2, A.City_Name, A.State_Abbreviation,A.ZIP_Code, OD.Deferred_Shipment_Date, OD.Item_Count,ODT.Text, OT.Text, P.Product_Description, S.Shipment_DateFROM Orders O, Order_Details OD, Products P, Customers C, Shipments S,Addresses A, Code_Translations ODT, Code_Translations OTWHERE UPPER(C.Last_Name) LIKE :Last_Name||%AND UPPER(C.First_Name) LIKE :First_Name||%AND OD.Order_ID = O.Order_IDAND O.Customer_ID = C.Customer_IDAND OD.Product_ID = P.Product_ID(+)AND OD.Shipment_ID = S.Shipment_ID(+)AND S.Address_ID = A.Address_ID(+)AND O.Status_Code = OT.CodeAND OT.Code_Type = ORDER_STATUSAND OD.Status_Code = ODT.CodeAND ODT.Code_Type = ORDER_DETAIL_STATUSAND O.Order_Date > :Now - 366ORDER BY C.Customer_ID, O.Order_ID DESC, S.Shipment_ID, OD.Order_Detail_ID;TablesOrders O,Order_Details OD,Products P,Customers C,Shipments S,Addresses A,Code_Translations ODT,Code_Translations OTJoinsOD.Order_ID = O.Order_IDO.Customer_ID = C.Customer_IDOD.Product_ID = P.Product_ID(+)OD.Shipment_ID =S.Shipment_ID(+)S.Address_ID = A.Address_ID(+)O.Status_Code = OT.CodeOD.Status_Code = ODT.CodeDan Tow – SQL TUNINGFiltersWHERE UPPER(C.Last_Name) LIKE :Last_Name||%AND UPPER(C.First_Name) LIKE :First_Name||%AND OT.Code_Type = ORDER_STATUSAND O.Order_Date > :Now – 366AND ODT.Code_Type = ORDER_DETAIL_STATUS
  • Layout tables and connectionsTablesOrders O,Order_Details OD,Products P,Customers C,Shipments S,Addresses A,Code_Translations ODT,Code_Translations OTJoinsOD.Order_ID = O.Order_IDO.Customer_ID = C.Customer_IDOD.Product_ID = P.Product_ID(+)OD.Shipment_ID = S.Shipment_ID(+)S.Address_ID = A.Address_ID(+)O.Status_Code = OT.CodeOD.Status_Code = ODT.CodeFSAODPODTCOTODan Tow – SQL TUNING
  • UnstructuredCopyright 2006JoinsOD.Order_ID = O.Order_IDO.Customer_ID = C.Customer_IDOD.Product_ID = P.Product_ID(+)OD.Shipment_ID = S.Shipment_ID(+)S.Address_ID = A.Address_ID(+)O.Status_Code = OT.CodeOD.Status_Code = ODT.CodeNeater, but can you do anything with it?What’s the optimal execution path?SAODP ODTCOTO
  • Parents and ChildrenJoinsOD.Order_ID = O.Order_IDO.Customer_ID = C.Customer_IDOD.Product_ID = P.Product_ID(+)OD.Shipment_ID = S.Shipment_ID(+)S.Address_ID = A.Address_ID(+)O.Status_Code = OT.CodeOD.Status_Code = ODT.CodeODTODPCAOSOTPrimary Key (unique index)No index or non-uniqueMasterDetailStructurethetree
  • VST – filters and best path Filters help determine best pathParentChildParentChildConcept:1. Start at most selective filter2. Join down first, before joining upwardsFiltersWHERE UPPER(C.Last_Name) LIKE :Last_Name||%AND UPPER(C.First_Name) LIKE :First_Name||%AND OT.Code_Type = ORDER_STATUS‘AND ODT.Code_Type = ORDER_DETAIL_STATUSAND O.Order_Date > :Now – 366 FF30%0.02%100% * (select count(*) from TAB where condition)---------------------------(select count(*) from Tab)SAODP ODTC OTO
  • FF30%0.02%SAODP ODTC OTOVST – best pathFF
  • FF30%0.02%SAODP ODTC OTOVST – best pathFF/*+ Leading (C,O,OT, OD ) */Dan TowSQL TUNING
  • T9.6T4T1.3MT2T6 T7.001T10.5T11 T12.5T13.2T3T8.7T14.9T15.8T16T5
  • T9.6T4T1.3MT2T6 T7.001T10.5T11 T12.5T13.2T3T8.7T14.9T15.8T16T5T7 -> T13
  • T9.6T4T1.3MT2T6T10.5T11 T12.5T3T8.7T14.9T15.8T16T5T7 -> T13T7 ->T13
  • T9.6T4T1.3MT2T6T10.5T11T3T8.7T14.9T15.8T16T5T7 -> T13T7 ->T13-> T12
  • T9.6T4T1.3MT6T10.5T11T3T8.7T14.9T15.8T16T5T7 -> T13T7 ->T13-> T12 ->T2
  • T9.6T4T1.3MT10.5T11T3T8.7T14.9T15.8T16T5T7 -> T13T7, T13, T12, T2 , T6
  • T9.6T4T1.3MT11T3T8.7T14.9T15.8T16T5T7 -> T13T7, T13, T12, T2 , T6, T10
  • T9.6T4T1.3MT3T8.7T14.9T15.8T16T5T7 -> T13T7, T13, T12, T2 , T6,T10, T11
  • T9.6T4T1.3MT3T8.7T14.9T16T5T7 -> T13T7, T13, T12, T2 , T6,T10, T11,T15
  • T9.6T4T1.3MT3T8.7T14.9T5T7 -> T13T7, T13, T12, T2 , T6,T10, T11,T15, T16
  • T9.6T4T1.3T3T8.7T14.9T5T7 -> T13T7, T13, T12, T2 , T6,T10, T11,T15, T16, M
  • T9.6T4T3T8.7T14.9T5T7 -> T13T7, T13, T12, T2, T6, T10, T11, T15, T16,M, T1
  • T9.6T3T8.7T14.9T5T7 -> T13T7, T13, T12, T2 , T6,T10, T11,T15, T16, M,T1, T4
  • T3T8.7T14.9T5T7 -> T13T7, T13, T12, T2 , T6,T10, T11,T15, T16, M,T1, T4,T9
  • T5T7 -> T13T7, T13, T12, T2 , T6,T10, T11,T15, T16, M,T1,T4,T9,T3,T8T14
  • T7, T13, T12, T2 , T6,T10, T11,T15, T16, M,T1,T4,T9,T3,T8T14, T5Why not Guess ?For 17 table join, there are 355 Trillion combinations
  • CartesianSELECTA.BROKER_ID BROKER_ID,A.BROKER_LAST_NAME BROKER_LAST_NAME,A.BROKER_FIRST_NAME BROKER_FIRST_NAME,A.YEARS_WITH_FIRM YEARS_WITH_FIRM,C.OFFICE_NAME OFFICE_NAME,SUM (B.BROKER_COMMISSION)TOTAL_COMMISSIONSFROMBROKER A,CLIENT_TRANSACTION B,OFFICE_LOCATION C,INVESTMENT IWHEREA.BROKER_ID = B.BROKER_ID ANDA.OFFICE_LOCATION_ID =C.OFFICE_LOCATION_IDGROUP BYA.BROKER_ID,A.BROKER_LAST_NAME,A.BROKER_FIRST_NAME,A.YEARS_WITH_FIRM,C.OFFICE_NAME;
  • Implied Cartesianselectc.client_first_name, c.client_last_name,ct.action, ct.price,b.broker_last_name, b.broker_first_name,o.office_namefromclient_transaction ct,client c,broker b,office_location owherect.price > 100and b.broker_id=ct.broker_idand c.broker_id = b.broker_idand o.office_location_id = b.office_location_id
  • Diagram work for Many to OneWhat about many to many?
  • UnstructuredCopyright 2006JoinsOD.Order_ID = O.Order_IDO.Customer_ID = C.Customer_IDOD.Product_ID = P.Product_ID(+)OD.Shipment_ID = S.Shipment_ID(+)S.Address_ID = A.Address_ID(+)O.Status_Code = OT.CodeOD.Status_Code = ODT.CodeSAODP ODTC OTOSAODP ODTCOTO
  • Many-to-One vs Many-to-ManyPredicate Filter123B -> C -> A go to A or C?Now what?
  • Adding ConstraintsSELECT COUNT (*)FROMb,c,aWHEREb.val2 = 100 ANDa.val1 = b.id ANDb.val1 = c.id;58 logical readsalter table c add constraint c_pk unique (id);alter table b add constraint b_pk unique (id);7 logical reads
  • 10053BC$: 4#: 1$: 5428#: 59999A$: 92#: 999B A CB C AC A BC B AA C BA B CTable: A Alias: ABest:: AccessPath: TableScanCost: 92.18 Degree: 1Resp: 92.18 Card: 999.00Best:: AccessPath: IndexRangeIndex: B_V2Cost: 4.00 Degree: 1Resp: 4.00 Card: 1.00Best:: AccessPath: IndexFFSIndex: C_PK_CONCost: 35.57 Degree: 1Resp: 35.57 Card: 59999.00Join order[1]: B[B]#0 A[A]#1 C[C]#2***************Now joining: A[A]#1***************Best:: JoinMethod: NestedLoopCost: 6.00 Degree: 1 Resp: 6.00 Card: 1.00 Bytes: 16***************Now joining: C[C]#2***************Best:: JoinMethod: NestedLoopCost: 6.00 Degree: 1 Resp: 6.00 Card: 1.00 Bytes: 21***********************Best so far: Table#: 0 cost: 4.0020 card: 1.0000 bytes: 12Table#: 1 cost: 6.0031 card: 1.0000 bytes: 16Table#: 2 cost: 6.0032 card: 1.0000 bytes: 21alter session set events=10053 trace name context forever;
  • No Unique ConstraintA$: 75#: 999B A CNL: $: 10#: 1B AC$: 6$: 4#: 1$: 8NL:$: 18#: 1B C ANL: $: 10#: 1B CA$: 6.01$: 4#: 1$: 8C A BC B A A C B A B CA$: 75#: 999C$: 5428#: 59999C$: 5428#: 59999AB C BJoin order[6]: C[C]#2 A[A]#1 B[B]#0Join order aborted: cost > best plan cost$HJ: $: 10#: 1
  • Unique ConstraintA$: 75#: 999B A CNL: $: 10#: 1B AC$: 6$: 4#: 1$: 8NL:$: 18#: 1B C ANL: $: 10#: 1B CA$: 5$: 4#: 1$: 7C A BC B A A C B A B CA$: 75#: 999C$: 5428#: 59999C$: 5428#: 59999AB C BJoin order[6]: C[C]#2 A[A]#1 B[B]#0Join order aborted: cost > best plan cost$HJ: $: 10#: 1NL:$: 16#: 1
  • Diagraming: what to do with many to many• With many to many we don’t know which direction to go• How an we improve the diagram?• -> Add two table join result set sizes
  • Join sizesJoin SizesUse the Joinsizes todetermine pathof leastresistance
  • Look at 3 queries• Query 1 runs more than 24 hours• Query 2 outer joins and scalar sub-queries• Query 3 create path not available to Oracle
  • Query 1 : Over 24 hours to runSELECTA0.zuchinis,A0.brocoli,C0.OrangesFROM(SELECTA1.planted_date,A1.pears,A1.zuchinis,A1.brocoliFROMFOO.A A1,(SELECTzuchinis,brocoliFROM FOO.A A2WHEREpears = M ANDplanted_date + 0 >= ADD_MONTHS ((SELECTMAX (planted_date)FROM FOO.B B1WHEREpears = M),- 11)GROUP BYzuchinis,brocoliHAVING COUNT (*) = 12)i2WHEREA1.planted_date = (SELECTMAX (planted_date)FROM FOO.B B2WHEREpears = M) ANDA1.pears = M ANDA1.zuchinis = i2.zuchinis (+) ANDA1.brocoli = i2.brocoli (+)UNIONSELECTA4.planted_date,A4.pears,A4.zuchinis,A4.brocoliFROM FOO.A A4WHEREA4.planted_date >01-OCT-08 and A4.planted_date <03-OCT-08 ANDA4.pears = D ANDA4.green_beans = 1AND NOT EXISTS (SELECT*FROM FOO.A A5WHEREpears = M ANDplanted_date = (SELECTMAX (planted_date)FROM FOO.B B3WHEREpears = M) ANDA4.zuchinis = A5.zuchinis ANDA4.brocoli = A5.brocoli))b,FOO.A A0,FOO.C C0,FOO.D D0,FOO.E E0WHEREA0.planted_date >01-OCT-08 andA0.planted_date <03-OCT-08 ANDA0.pears = D ANDA0.green_beans = 1 ANDA0.zuchinis = b.zuchinis ANDA0.brocoli = b.brocoli ANDA0.planted_date = C0.planted_date ANDA0.pears = C0.pears ANDA0.zuchinis = C0.zuchinis ANDA0.brocoli = C0.brocoli ANDA0.planted_date = D0.planted_date ANDA0.pears = D0.pears ANDA0.harvest_size = D0.harvest_size ANDC0.Oranges = D0.Oranges ANDC0.apples = D0.apples AND(D0.lemons = 0 ORD0.lemons IS NULL) ANDA0.planted_date = E0.planted_date ANDA0.pears = E0.pears ANDA0.harvest_size = E0.harvest_size ANDC0.Oranges = E0.Oranges ANDC0.apples = E0.apples AND(E0.lemons = 0 ORE0.lemons IS NULL)ORDER BYA0.zuchinis, A0.brocoli;
  • Visual SQL Diagram9 secs
  • Default vs TunedDefaultTuned
  • Where is the map?
  • Comparing Plans : 24 hours to 5 minsNLNLNLNLHJHJNLNL
  • Q2SELECT CASE WHEN M.NYC IS NULL THEN (SELECT /*+ qb_name(qb1) */ MAX (Kona)FROM foo.FWHERE harvest_date = to_date(08/10/2008,dd/mm/yyyy)AND Argentina = TRIM (D) AND Norway = F_OUTER.NorwayELSE M.NYC END AS NYC,CASE WHEN F_OUTER.Perth IS NULL THEN NULLELSE (SELECT /*+ qb_name(qb2) */ Georgia FROM foo.PWHERE harvest_date = to_date(08/10/2008,dd/mm/yyyy)AND Argentina = TRIM (D) AND Paris = F_OUTER.Perth)END AS richard,CASE WHEN F_OUTER.Aruba IS NULL THEN NULLELSE (SELECT /*+ qb_name(qb3) */ Georgia FROM foo.PWHERE harvest_date = to_date(08/10/2008,dd/mm/yyyy)AND Argentina = TRIM (D) AND Paris = F_OUTER.Aruba)END AS Jody,CASE WHEN F_OUTER.Portland IS NULL THEN NULLELSE (SELECT /*+ qb_name(qb4) */ Georgia FROM foo.PWHERE harvest_date = to_date(08/10/2008,dd/mm/yyyy)AND Argentina = TRIM (D) AND Paris = F_OUTER.Portland)END AS TomFROM foo.F F_OUTER, foo.M , foo.J , foo.N ,(SELECT /*+ qb_name(qb5) */ H.SF, Oregon, H.Haiti, K.Bermuda, L.DenmarkFROM (foo.H LEFT OUTER JOIN foo.KON H.harvest_date = K.harvest_dateAND H.Argentina = K.Argentina AND H.SF = K.SFAND K.Dallas = 001)LEFT OUTER JOIN FOo.LON H.harvest_date = L.harvest_dateAND H.Argentina = L.Argentina AND H.SF = L.SFWHERE H.harvest_date = to_date(08/10/2008,dd/mm/yyyy)AND H.Argentina = TRIM (D)) extraWHERE F_OUTER.harvest_date = M.harvest_date(+)AND F_OUTER.Argentina = M.Argentina(+)AND F_OUTER.Norway = M.Norway(+)AND M.Norway(+) = M.Texas(+)AND F_OUTER.harvest_date = to_date(08/10/2008,dd/mm/yyyy)AND F_OUTER.Argentina = TRIM (D)AND M.harvest_date(+) = to_date(08/10/2008,dd/mm/yyyy)AND M.Argentina(+) = TRIM (D)AND F_OUTER.Norway = F_OUTER.HawaiiAND F_OUTER.harvest_date = J.harvest_date(+)AND F_OUTER.Argentina = J.Argentina(+)AND F_OUTER.Norway = J.Texas(+)AND J.harvest_date(+) = to_date(08/10/2008,dd/mm/yyyy)AND J.Argentina(+) = TRIM (D)AND F_OUTER.Iraq = extra.SF(+)AND F_OUTER.harvest_date = N.harvest_date(+)AND F_OUTER.Argentina = N.Argentina(+)AND F_OUTER.Norway = N.Hawaii(+)AND N.Jordon(+) = 0/
  • Scalar Sub-queries12825845682348
  • Q2The subqueries in the select clause look likeselect CASE WHEN F.f1 IS NULLTHEN NULLELSE (SELECT X.f2FROM XWHERE code_vl = F.f1)END AS f0from F;and should be merged into the query like:select CASE WHEN F.f1 IS NULLTHEN NULLELSE ( X.f2)END AS f0from F , Xwhere code_vl(+) = F.f1;select CASE WHEN F.f1 IS NULLTHEN NULLELSE (SELECT X.f2FROM XWHERE code_vl = F.f2)END AS f0from F;select CASE WHEN F.f1 IS NULLTHEN NULLELSE ( X.f2)END AS f0from F , Xwhere code_vl(+) = F.f1;
  • Q3SELECT DISTINCT *FROMFOO.a a, FOO.c c, FOO.d d, FOO.g gWHEREa.planted_date > 01-OCT-08 ANDa.planted_date < 03-OCT-08 ANDa.pears = D AND a.green_beans = 1 ANDa.planted_date = c.planted_date ANDa.pears = c.pears ANDa.zuchinis = c.zuchinis ANDa.brocoli = c.brocoli ANDa.planted_date = d.planted_date ANDa.pears = d.pears ANDa.harvest_size = d.harvest_size ANDc.oranges = d.oranges ANDc.apples = d.apples AND(d.lemons = 0 OR d.lemons IS NULL) ANDa.planted_date = g.planted_date ANDa.pears = g.pears ANDa.harvest_size = g.harvest_size ANDc.oranges = g.oranges ANDc.apples = g.apples AND(g.lemons = 0 OR g.lemons IS NULL) ANDa.zuchinis = 0236 ANDd.apples = g.apples ANDd.oranges = g.orangesORDER BY a.zuchinis, a.brocoli;
  • Q3: Transitivity81 6/22/20131,126,4027,136,362
  • Q382 6/22/2013SELECT * FROM(SELECT /*+ NO_MERGE */ c.apples, c.oranges, a.harvest_sizeFROM a, cWHEREa.planted_date = TO_DATE (02/10/2008, dd/mm/yyyy) ANDa.pears = D ANDa.green_beans = 1 ANDa.planted_date = c.planted_date ANDa.pears = c.pears ANDa.zuchinis = c.zuchinis ANDa.brocoli = c.brocoli ANDa.zuchinis = 0236) X,(SELECT /*+ NO_MERGE */ d.apples, d.oranges, d.harvest_sizeFROM d, gWHEREd.planted_date = TO_DATE (02/10/2008, dd/mm/yyyy) ANDg.planted_date = TO_DATE (02/10/2008, dd/mm/yyyy) ANDg.apples = d.apples ANDd.oranges = g.oranges ANDd.pears = D ANDg.pears = D ANDg.pears = d.pears ANDg.harvest_size = d.harvest_size AND(d.lemons = 0 OR d.lemons IS NULL) AND(g.lemons = 0 OR g.lemons IS NULL)) YWHEREX.oranges = Y.oranges ANDX.apples = Y.apples ANDX.harvest_size = Y.harvest_size;This final version runs inelapsed 0.33 secs and 12K logical readsdown from an originalelapsed 4.5 secs and 1M logical reads
  • HINTS• Leading (tab_alias , table_alias … ) 10g (9i use ORDERED, not as good )• USE_NL (table_alias) – Inner Table (2cd in xpla not driving)• USE_HASH (table_alias) – probe into (1st in xplan)• INDEX (tab_alias index_name)• NO_MERGEOracle first decides join order then join type(example http://www.adp-gmbh.ch/blog/2008/01/17.php)83 6/22/2013
  • FF30%0.02%SAODP ODTC OTOLeading Hint, use table alias (not table)FF/*+ Leading (C,O,OT, OD ) */
  • HJXY Hash XresultsYNLXY YXselect /*+ LEADING(X,Y) USE_HASH(Y) */ *select /*+ LEADING(X,Y) USE_NL(Y) */ *
  • What tools to use to create VST diagrams?• Paper– Modifications messy and difficult• PowerPoint– Can move things around– Sticky connectors– Easy to modify• DB Optimizer– Automatic and still modifiable
  • VST Steps Summary1.Diagram tables2.Draw connectors for each join3.Calculate filter ratio1.If many to many thencalculate two table join sizesExecution Path• Start at the most selective join filter• Join to keep the running result set size smallMany to Many relationships = problems6/22/2013ParentChildParentChildFF30%0.02%SAODP ODTC OTO
  • SELECTO.ORDER_ID,LINE_ITEM_ID,PRODUCT_ID,UNIT_PRICE,QUANTITY,ORDER_MODE,ORDER_STATUS,ORDER_TOTAL,SALES_REP_ID,PROMOTION_ID,C.CUSTOMER_ID,CUST_FIRST_NAME,CUST_LAST_NAME,CREDIT_LIMIT,CUST_EMAIL,ORDER_DATEFROMORDERS O,ORDER_ITEMS OI,CUSTOMERS CWHEREO.ORDER_ID = OI.ORDER_ID ANDO.CUSTOMER_ID = C.CUSTOMER_ID ANDO.ORDER_STATUS <= 4VST vs Explain PlanMJ FF
  • Graphical Explain Plan
  • Visual SQL Tuning (VST)Table SizesJoin SizesFilter RatiosExists
  • Execution Plan
  • Summary1.Database - AAS– Profile database– Use wait interface and graphics– Identify machine, application, database or SQL2.SQL - VST– Indexes, stats, execution path– Visual SQL Tuning
  • END
  • View Expansion
  • View Expansion
  • Types of Subqueries• subquery– query in where clause– Select 1 from dual where 1 = (select 1 from dual);• correlated subquery– Subquery uses fields from outer query– Select 1 from dual a where 1=(select 1 from dual b wherea.dummy=b.dummy)• scalar subquery– Query in select list– Returns 1 value or null , ie scalar– Select (select 1 from dual) from dual;• inline views– Query in from clause– Select 1 from dual a, (select 1 from dual ) b;
  • Visual SQL Tuning
  • • Layout tables Graphically– Details tables above Masters– One to one relations side by side– Many to many any which wayMany tosingle value
  • Join Set SizesJoin type max result set sizepossiblenotesone-to-scalar A this is equivalent to a filter on Atable B returns one value like a max(), min(),count() etcone-to-one min(rA,rB)one-to-many rAJoining from A to B will not increase the result setsizemany-to-many rA*rB-------------------------min(ndv(A),ndv(B))The more duplicates in both tables the greaterchancethe result set size will explode99 6/22/2013We can say a lot about the join set size between two tables just by thejoin type and the number of rows in the table and NDV in the join column,but the easiest way most often is just to extract the two table joins andrun a count(*) on that subset of the query
  • Join Filter ratiosAB Jm=1Jd ~> 1FKPKAB Jm <= 1Jd ~> 1detailMasterUniqueindex oruniqueconstraintJd, = join detail ratio , the avg number of rows returned when joining from the master to childJm = master join ratio, the avg number of rows returned joining from the child into the master.Jm = 1 when PK/FK relations,Jm < 1 possible when unique indexes or unique constraints instead of PK/FK.Jd < 1 rare but acts as filter instead of a multiplier
  • Hash Join vs NLCol ACol BCol C Filter &Join IndexCol DTable YTable XFilter IndexJoin IndexCol ACol BCol CFilter IndexJoin IndexCol DTable YTable XFilter IndexJoin IndexNL HJDriving Table (smaller set)Drive from Table Y off of set of rowsreturned from filter on column CNested loops into Table X on Index onJoinFilter results without Index even thoughindex on filter columnCreate hash result set on Table Y fromfilter on column CProbe hash result set with rows fromfilter on table X on column AFilter IndexJoin IndexBuild Hash TableProbe Hash TableNLXYHJXY
  • Left Deep HJHJHJHJT1T2T3T4T1 T2T3T4HJHJHJT1 T2T3HashedHashed probeprobeT4probeHashed
  • Right Deep HJHJT4HJT3HJT2T1T2 T1T3T4HJHJHJT2 T1T3T4probehashedhashedhashedprobeprobe
  • Nest Loops left deepT1 T2T3T4NLNLNLT1T2T3T4NLNLNLprobedprobedprobed
  • Nest Loops can’t be right deepT3 T4T2T1 NLT1NLT2NLT3T4probedprobedprobedNLNLNL
  • BushyT1 T2HJNLT1T2NLT3T4NLT3 T4NLHJselect t3id, a.*, b.* from( select /*+ no_merge */t2.id t2id, t1.data t1data, t2.data t2datafrom t1, t2where t1.id = t2.id ) a,( select /*+ no_merge */t3.id t3id, t3.data t3data, t4.data t4datafrom t3, t4where t3.id = t4.id ) bwhere a.t2id=b.t3id/