Obtaining and Interpreting Execution Plans using DBMS_XPLAN David Kurtz Go-Faster Consultancy Ltd. david.kurtz@go-faster.co.uk www.go-faster.co.uk Who Am I? • Oracle Database Specialist – Independent consultant • System Performance tuning • Book – www.psftdba.com – PeopleSoft ERP – Oracle RDBMS DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 2 Resources • If you can’t hear me say so now. • Please feel free to ask questions as we go along. • The presentation is available from • Conference website • www.go-faster.co.uk DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 3 My Motivation • Performance problems are instinctively routed to the DBA • SQL Trace can locate a database problem • Execution plan will show you what Oracle is doing. • Many problems are caused by ‘poor SQL’ • I often have to rewrite the SQL. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 4 Your Motivation • How to ask your DBA the right questions. • How to answer some of those questions yourself • How to find out how the database is executing a problematic SQL statement DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 5 Caveat • I cannot, in one session, cover everything you need to know. • But I can give you enough to get started on your own. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 6 DBA’s Chief Weapons in the Performance Fight with Development • Surprise and Fear – “Surprise! Surprise! The application runs slowly” – “I’m afraid I can’t do anything about it. It’s a problem with the application code.” • It doesn’t have to be like this. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 7 Agenda • SQL Trace • Execution Plans – – – – Explain Plan For DBMS_XPLAN AWR Licensing DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 8 What is SQL trace? • Oracle shadow process writes a file on the database server • Trace file contains – – – – User and recursive SQL statements Execution plan, physical & logical reads Timing information Wait and bind information (optional) DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 9 What’s the advantage of SQL Trace? • You know how long each statement took to execute – Not just an estimate of how long • The execution plan is what really happened • You can find out how long each line of an execution plan took to execute – So you know where in the plan the problem is located. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 10 What’s the problem with SQL Trace? • If you’re not the DBA: – The trace file is on the database server • udump/bdump directories – It is usually only readable by members of the DBA group. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 11 What’s the problem with SQL Trace? • Reactive – Run process with trace and respond to what happened. • And sometimes – You don’t get the execution plan because the plan is only written to the trace file when the cursor is closed. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 12 Alternatives to Trace • Explain Plan For • DBMS_XPLAN • Assumption: – You know which SQL statement is your problem! DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 13 Example: Two HR tables • PS_NAMES Name ----------------------EMPLID* NAME_TYPE EFFDT EFF_STATUS COUNTRY_NM_FORMAT NAME … DBMS_XPLAN Null? -------NOT NULL NOT NULL NOT NULL NOT NULL NOT NULL NOT NULL • PS_DEPT_TBL Type -----------VARCHAR2(11) VARCHAR2(3) DATE VARCHAR2(1) VARCHAR2(3) VARCHAR2(50) Name ----------------------SETID* DEPTID* EFFDT* EFF_STATUS DESCR DESCRSHORT … Null? -------NOT NULL NOT NULL NOT NULL NOT NULL NOT NULL NOT NULL UKOUG2008 ©www.go-faster.co.uk Type -----------VARCHAR2(5) VARCHAR2(10) DATE VARCHAR2(1) VARCHAR2(30) VARCHAR2(10) 14 A sample SQL SELECT d.setid, d.deptid, d.descr, n.emplid, n.name FROM ps_dept_tbl d, ps_names n WHERE d.effdt = ( SELECT MAX(d1.effdt) FROM ps_dept_tbl d1 WHERE d1.setid = d.setid AND d1.deptid = d.deptid AND d1.effdt <= SYSDATE) AND d.eff_status = 'A' AND n.emplid = d.manager_id / DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 15 Explain Plan For • Writes to plan_table table – This is the way we used to do it up to Oracle 8i EXPLAIN PLAN SET statement_id = 'TST‘ INTO plan_table FOR <SQL> / DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 16 Explain Plan For • Then you had to query the plan table SELECT id, parent_id, lpad(' ', 2*(level-1))||operation||' '||options||' '||object_name||' '|| decode(id, 0, 'Cost = '||position) query_plan FROM plan_table START WITH id = 0 AND statement_id = 'TST' CONNECT BY prior id = parent_id AND statement_id = 'TST' ; DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 17 Explain Plan For • And you get an execution plan with a cost ID P Query Plan --- --- -----------------------------------------0 SELECT STATEMENT Cost = 13 1 0 NESTED LOOPS 2 1 HASH JOIN 3 2 TABLE ACCESS FULL PS_DEPT_TBL 4 2 VIEW VW_SQ_1 5 4 HASH GROUP BY 6 5 INDEX FAST FULL SCAN PS1DEPT_TBL 7 1 TABLE ACCESS BY INDEX ROWID PS_NAMES 8 7 INDEX RANGE SCAN PS_NAMES DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 18 Explain Plan For • Then you had to query the plan table SELECT id, parent_id, lpad(' ', 2*(level-1))||operation||' '||options||' '||object_name||' '|| decode(id, 0, 'Cost = '||position) query_plan FROM plan_table START WITH id = 0 AND statement_id = 'TST' CONNECT BY prior id = parent_id AND statement_id = 'TST' ; DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 19 DBMS_XPLAN • Oracle supplied package procedure – Documented in PL/SQL Package and Types Reference manual. • • • • • DISPLAY – 9i DISPLAY_CURSOR – 10g DISPLAY_AWR -10g DISPLAY_SQLSET – 10g DISPLAY_SQL_PLAN_BASELINE – 11g DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 20 DBMS_XPLAN.DISPLAY • Displays contents of the plan table – Most recently explained statement – Or a named statement • Available in Oracle 9i – No licence restrictions DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 21 DBMS_XPLAN.DISPLAY • Usage DBMS_XPLAN.DISPLAY ( table_name IN VARCHAR2 DEFAULT 'PLAN_TABLE' , statement_id IN VARCHAR2 DEFAULT NULL , format IN VARCHAR2 DEFAULT 'TYPICAL' , filter_preds IN VARCHAR2 DEFAULT NULL); DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 22 DBMS_XPLAN.DISPLAY • Formats – BASIC: basic execution plan, no metrics – TYPICAL: default. Most of the relavent information – SERIAL: like typical, but without any parallel execution information – ALL: like typical but also include projection, alias and remote SQL. – ADVANCED: like all but also includes the OUTLINE • Not in the Oracle 10g documentation, but it works on 10g DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 23 DBMS_XPLAN.DISPLAY SELECT * FROM table(dbms_xplan.display()); • Autotrace in SQL*Plus 10 now uses dbms_xplan. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 24 select * from table( dbms_xplan.display( null, null, 'TYPICAL')); Plan hash value: 454993881 -------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 2 | 176 | 13 (16)| 00:00:01 | | 1 | NESTED LOOPS | | 2 | 176 | 13 (16)| 00:00:01 | |* 2 | HASH JOIN | | 1 | 65 | 11 (19)| 00:00:01 | |* 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 330 | 14850 | 6 (0)| 00:00:01 | | 4 | VIEW | VW_SQ_1 | 660 | 13200 | 4 (25)| 00:00:01 | | 5 | HASH GROUP BY | | 660 | 13860 | 4 (25)| 00:00:01 | |* 6 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 660 | 13860 | 3 (0)| 00:00:01 | | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 2 | 46 | 2 (0)| 00:00:01 | |* 8 | INDEX RANGE SCAN | PS_NAMES | 2 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------------Predicate Information (identified by operation id): --------------------------------------------------2 - access("D"."EFFDT"="VW_COL_1" AND SYS_OP_DESCEND("D"."EFFDT")=SYS_OP_DESCEND( "VW_COL_1") AND "SETID"="D"."SETID" AND "DEPTID"="D"."DEPTID") 3 - filter("D"."EFF_STATUS"='A') 6 - filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("EFFDT"))<=SYSDATE@! AND SYS_OP_DESCEND("EFFDT")>=SYS_OP_DESCEND(SYSDATE@!)) 8 - access("N"."EMPLID"="D"."MANAGER_ID") DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 25 More Formats • `ROWS - if relevant, shows the number of rows estimated by the optimizer • BYTES - if relevant, shows the number of bytes estimated by the optimizer • COST - if relevant, shows optimizer cost information • PARTITION - if relevant, shows partition pruning information • PARALLEL - if relevant, shows PX information (distribution method and table queue information) • PREDICATE - if relevant, shows the predicate section • PROJECTION -if relevant, shows the projection section • ALIAS - if relevant, shows the "Query Block Name / Object Alias" section • REMOTE - if relevant, shows the information for distributed query (for example, remote from serial distribution and remote SQL) • NOTE - if relevant, shows the note section of the explain plan DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 26 table( dbms_xplan.display( null, null, 'TYPICAL,-BYTES')); select * from Plan hash value: 454993881 -----------------------------------------------------------------------------------| Id | Operation | Name | Rows | Cost (%CPU)| Time | -----------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 2 | 13 (16)| 00:00:01 | | 1 | NESTED LOOPS | | 2 | 13 (16)| 00:00:01 | |* 2 | HASH JOIN | | 1 | 11 (19)| 00:00:01 | |* 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 330 | 6 (0)| 00:00:01 | | 4 | VIEW | VW_SQ_1 | 660 | 4 (25)| 00:00:01 | | 5 | HASH GROUP BY | | 660 | 4 (25)| 00:00:01 | |* 6 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 660 | 3 (0)| 00:00:01 | | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 2 | 2 (0)| 00:00:01 | |* 8 | INDEX RANGE SCAN | PS_NAMES | 2 | 1 (0)| 00:00:01 | -----------------------------------------------------------------------------------Predicate Information (identified by operation id): --------------------------------------------------2 - access("D"."EFFDT"="VW_COL_1" AND SYS_OP_DESCEND("D"."EFFDT")=SYS_OP_DESCEND( "VW_COL_1") AND "SETID"="D"."SETID" AND "DEPTID"="D"."DEPTID") 3 - filter("D"."EFF_STATUS"='A') 6 - filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("EFFDT"))<=SYSDATE@! AND SYS_OP_DESCEND("EFFDT")>=SYS_OP_DESCEND(SYSDATE@!)) 8 - access("N"."EMPLID"="D"."MANAGER_ID") DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 27 select * from table( dbms_xplan.display( null, null, ‘ALL')); • Additional Information Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------1 3 4 5 6 7 8 - SEL$C772B8D1 SEL$C772B8D1 SEL$683B0107 SEL$683B0107 SEL$683B0107 SEL$C772B8D1 SEL$C772B8D1 DBMS_XPLAN / D@SEL$1 / VW_SQ_1@SEL$7511BFD2 / D1@SEL$2 / N@SEL$1 / N@SEL$1 UKOUG2008 ©www.go-faster.co.uk 28 Specify Query Block Names SELECT /*+QB_NAME(MAIN_QUERY)*/ d.setid, d.deptid, d.descr, n.emplid, n.name FROM ps_dept_Tbl d, ps_names n WHERE d.effdt = ( SELECT /*+QB_NAME(DEPT_SUBQUERY)*/ MAX(d1.effdt) FROM ps_dept_tbl d1 WHERE d1.setid = d.setid AND d1.deptid = d.deptid AND d1.effdt <= SYSDATE ) AND d.eff_status = 'A' AND n.emplid = d.manager_id / DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 29 select * from table( dbms_xplan.display( null, null, ‘ALL')); • Additional Information Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------1 3 4 5 6 7 8 - SEL$3787FDDA SEL$3787FDDA SEL$71F31171 SEL$71F31171 SEL$71F31171 SEL$3787FDDA SEL$3787FDDA DBMS_XPLAN / D@MAIN_QUERY / VW_SQ_1@SEL$4A7F38AA / D1@DEPT_SUBQUERY / N@MAIN_QUERY / N@MAIN_QUERY UKOUG2008 ©www.go-faster.co.uk 30 select * from table( dbms_xplan.display( null, null, ‘ALL')); • Additional Information Column Projection Information (identified by operation id): ----------------------------------------------------------1 - (#keys=0) "D"."SETID"[VARCHAR2,5], "D"."DEPTID"[VARCHAR2,10], "D"."DESCR"[VARCHAR2,30], "N"."EMPLID"[VARCHAR2,11], "N"."NAME"[VARCHAR2,50] 2 - (#keys=4) "D"."SETID"[VARCHAR2,5], "D"."DEPTID"[VARCHAR2,10], "D"."DESCR"[VARCHAR2,30], "D"."MANAGER_ID"[VARCHAR2,11] 3 - "D"."SETID"[VARCHAR2,5], "D"."DEPTID"[VARCHAR2,10], "D"."EFFDT"[DATE,7], "D"."DESCR"[VARCHAR2,30], "D"."MANAGER_ID"[VARCHAR2,11] 4 - "VW_COL_1"[DATE,7], "SETID"[VARCHAR2,5], "DEPTID"[VARCHAR2,10] 5 - (#keys=2) "D1"."SETID"[VARCHAR2,5], "D1"."DEPTID"[VARCHAR2,10], MAX(SYS_OP_UNDESCEND(SYS_OP_DESCEND("EFFDT")))[7] 6 - "D1"."SETID"[VARCHAR2,5], "D1"."DEPTID"[VARCHAR2,10], SYS_OP_DESCEND("EFFDT")[RAW,12] 7 - "N"."EMPLID"[VARCHAR2,11], "N"."NAME"[VARCHAR2,50] 8 - "N".ROWID[ROWID,10], "N"."EMPLID"[VARCHAR2,11] DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 31 select * from table( dbms_xplan.display( null, null, ‘ADVANCED')); • An outline is a set of hints Outline Data ------------/*+ BEGIN_OUTLINE_DATA INDEX(@"SEL$2" "D1"@"SEL$2" "PS_DEPT_TBL") USE_HASH(@"SEL$1" "N"@"SEL$1") LEADING(@"SEL$1" "D"@"SEL$1" "N"@"SEL$1") INDEX_FFS(@"SEL$1" "N"@"SEL$1" "PS0NAMES") FULL(@"SEL$1" "D"@"SEL$1") OUTLINE(@"SEL$1") OUTLINE(@"SEL$2") OUTLINE_LEAF(@"SEL$1") OUTLINE_LEAF(@"SEL$2") ALL_ROWS OPTIMIZER_FEATURES_ENABLE('10.2.0.1') IGNORE_OPTIM_EMBEDDED_HINTS END_OUTLINE_DATA */ DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 32 DBMS_XPLAN.DISPLAY • Filter Predicates – Applied to the plan table – Simply get a partial execution plan DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 33 table( dbms_xplan.display(null, null, null, 'object_name like ''%DEPT%''')); select * from Plan hash value: 454993881 ---------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------|* 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 330 | 14850 | 6 (0)| 00:00:01 | |* 6 | INDEX FAST FULL SCAN| PS1DEPT_TBL | 660 | 13860 | 3 (0)| 00:00:01 | ---------------------------------------------------------------------------------------Predicate Information (identified by operation id): --------------------------------------------------3 - filter("D"."EFF_STATUS"='A') 6 - filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("EFFDT"))<=SYSDATE@! AND SYS_OP_DESCEND("EFFDT")>=SYS_OP_DESCEND(SYSDATE@!)) DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 34 SQL Developer Explain Plan DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 35 DBMS_XPLAN.DISPLAY • Rolled-up cost of each operation – Estimate of time (converted from cost to time) – Number of rows returned from each operation. • Remember this is an prediction of what will happen based upon the CBO statistics and not reality. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 36 The problem with EXPLAIN PLAN • It is the execution plan now in this session with the statistics and environment in force now. • It may be what will happen next time the statement is executed, but it may not be what happened last time. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 37 DBMS_XPLAN.DISPLAY_CURSOR • Displays the execution plan of a cursor in the library cache – Based upon view V$SQL_PLAN_STATISTICS_ALL – A SQL Statement might have multiple execution plans • So it is what happened – sort of DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 38 DBMS_XPLAN.DISPLAY_CURSOR • Usage DBMS_XPLAN.DISPLAY_CURSOR( sql_id IN VARCHAR2 DEFAULT NULL, child_number IN NUMBER DEFAULT NULL, format IN VARCHAR2 DEFAULT 'TYPICAL'); DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 39 DBMS_XPLAN.DISPLAY_CURSOR • Get SQL ID – – – – V$SQL V$SQLAREA V$OPEN_CURSOR V$SESSION DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 40 table( dbms_xplan.display_cursor( 'bh01rt8q2820q')); select * from PLAN_TABLE_OUTPUT ------------------------------------------------------SQL_ID bh01rt8q2820q, child number 0 ------------------------------------SELECT d.setid, d.deptid, d.descr, n.emplid, n.name FROM ps_dept_Tbl d, ps_names n WHERE d.effdt = ( SELECT MAX(d1.effdt) FROM ps_dept_tbl d1 WHERE d1.setid = d.setid AND d1.deptid = d.deptid AND d1.effdt <= SYSDATE ) AND d.eff_status ='A' AND n.emplid = d.manager_id … DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 41 table( dbms_xplan.display_cursor( 'bh01rt8q2820q')); select * from Plan hash value: 454993881 -------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 13 (100)| | | 1 | NESTED LOOPS | | 2 | 176 | 13 (16)| 00:00:01 | |* 2 | HASH JOIN | | 1 | 65 | 11 (19)| 00:00:01 | |* 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 330 | 14850 | 6 (0)| 00:00:01 | | 4 | VIEW | VW_SQ_1 | 660 | 13200 | 4 (25)| 00:00:01 | | 5 | HASH GROUP BY | | 660 | 13860 | 4 (25)| 00:00:01 | |* 6 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 660 | 13860 | 3 (0)| 00:00:01 | | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 2 | 46 | 2 (0)| 00:00:01 | |* 8 | INDEX RANGE SCAN | PS_NAMES | 2 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------------Predicate Information (identified by operation id): --------------------------------------------------2 - access("D"."EFFDT"="VW_COL_1" AND SYS_OP_DESCEND("D"."EFFDT")=SYS_OP_DESCEND( "VW_COL_1") AND "SETID"="D"."SETID" AND "DEPTID"="D"."DEPTID") 3 - filter("D"."EFF_STATUS"='A') 6 - filter((SYS_OP_UNDESCEND("D1"."SYS_NC00051$")<=SYSDATE@! AND "D1"."SYS_NC00051$">=SYS_OP_DESCEND(SYSDATE@!))) 8 - access("N"."EMPLID"="D"."MANAGER_ID") DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 42 DBMS_XPLAN.DISPLAY_CURSOR • The execution plan is the one that was used to execute the statement – But the costs and metrics are still based upon the CBO statistics – There may be a discrepancy between estimated and actual cost of operations in the plan DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 43 Descending and Function-Based Indexes SELECT uic.index_name, uic.column_name, uic.descend, uie.column_expression FROM user_ind_Columns uic , user_ind_expressions uie WHERE uic.column_name = 'SYS_NC00051$' AND uic.index_name = 'PS1DEPT_TBL' AND uie.index_name = uic.index_name AND uie.table_name = uic.table_name / INDEX_NAME COLUMN_NAME DESCEND COLUMN_EXPRESSION ------------ ------------ ------- ----------------PS1DEPT_TBL SYS_NC00051$ DESC "EFFDT" DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 44 Extra Format Options • IOSTAT: assumes basic statistics are collected when SQL executed • MEMSTATS: if PGA management enable display memory management stats • ALLSTATS: IOSTATS and MEMSTATS • LAST: last execution only DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 45 Collecting Execution Statistics • Hint one statement /*+ gather_plan_statistics */ • Set for session ALTER SESSION SET statistics_level = 'ALL' DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 46 select * from table(dbms_xplan.display_cursor( 'fz3qdn0z07n8n',null,'IOSTATS')); SQL_ID fz3qdn0z07n8n, child number 0 ------------------------------------SELECT /*+ gather_plan_statistics */ d.setid, d.deptid, d.descr, n.emplid, n.name FROM ps_dept_Tbl d ps_names n WHERE d.effdt = ( SELECT MAX(d1.effdt) FROM ps_dept_tbl d1 WHERE d1.setid = d.setid AND d1.deptid = d.deptid AND d1.effdt <= SYSDATE ) AND d.eff_status = 'A' AND n.emplid = d.manager Plan hash value: 454993881 ---------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers ---------------------------------------------------------------------------------------------------| 1 | NESTED LOOPS | | 1 | 2 | 65 |00:00:00.01 | 793 |* 2 | HASH JOIN | | 1 | 1 | 618 |00:00:00.01 | 40 |* 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 1 | 330 | 658 |00:00:00.01 | 23 | 4 | VIEW | VW_SQ_1 | 1 | 660 | 620 |00:00:00.01 | 17 | 5 | HASH GROUP BY | | 1 | 660 | 620 |00:00:00.01 | 17 |* 6 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 1 | 660 | 660 |00:00:00.01 | 17 | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 618 | 2 | 65 |00:00:00.01 | 753 |* 8 | INDEX RANGE SCAN | PS_NAMES | 618 | 2 | 65 |00:00:00.01 | 691 ---------------------------------------------------------------------------------------------------- DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk | | | | | | | | | 47 select * from table(dbms_xplan.display_cursor( 'fz3qdn0z07n8n',null,'MEMSTATS')); SQL_ID fz3qdn0z07n8n, child number 0 ------------------------------------SELECT /*+ gather_plan_statistics */ d.setid, d.deptid, d.descr, n.emplid, n.name FROM ps_dept_Tbl d ps_names n WHERE d.effdt = ( SELECT MAX(d1.effdt) FROM ps_dept_tbl d1 WHERE d1.setid = d.setid AND d1.deptid = d.deptid AND d1.effdt <= SYSDATE ) AND d.eff_status = 'A' AND n.emplid = d.manager Plan hash value: 454993881 ---------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | OMem | ---------------------------------------------------------------------------------------------------| 1 | NESTED LOOPS | | 1 | 2 | 65 |00:00:00.01 | | |* 2 | HASH JOIN | | 1 | 1 | 618 |00:00:00.01 | 746K| |* 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 1 | 330 | 658 |00:00:00.01 | | | 4 | VIEW | VW_SQ_1 | 1 | 660 | 620 |00:00:00.01 | | | 5 | HASH GROUP BY | | 1 | 660 | 620 |00:00:00.01 | | |* 6 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 1 | 660 | 660 |00:00:00.01 | | | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 618 | 2 | 65 |00:00:00.01 | | |* 8 | INDEX RANGE SCAN | PS_NAMES | 618 | 2 | 65 |00:00:00.01 | | ---------------------------------------------------------------------------------------------------- DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 1Mem | | 746K| | | | | | | O/1/M | 1/0/0| | | | 48 MEMSTATS Columns • 0Mem : The estimated amount of memory needed for an optimal execution • 1Mem : The estimated amount of memory needed for one-pass execution. • 0/1/M : Then number of times the execution was performed in optimal/onepass/multipass mode. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 49 DBMS_XPLAN.DISPLAY_AWR • Displays the execution plan of a cursor stored in the Automatic Workload Repository (AWR) • Extracts information from AWR tables – DBA_HIST_SQL_PLAN – DBA_HIST_SQLTEXT DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 50 DBMS_XPLAN.DISPLAY_AWR • AWR is the replacement to Statspack – It is licensed as a part of Diagnostic Pack – Therefore, use of this function is similarly licensed. • Statspack doesn’t report SQL_IDs DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 51 Statspack and DBMS_XPLAN select * from table( dbms_xplan.display( 'stats$sql_plan',null, 'all', 'hash_value = 740558870 and snap_id=4200')) • If you use 10g STATSPACK, use hash_value, not plan_hash_value DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 52 DBMS_XPLAN.DISPLAY_AWR • Usage DBMS_XPLAN.DISPLAY_AWR( sql_id IN VARCHAR2, plan_hash_value IN NUMBER DEFAULT NULL, db_id IN NUMBER DEFAULT NULL, format IN VARCHAR2 DEFAULT TYPICAL); DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 53 DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 54 table( dbms_xplan.display_awr( 'bh01rt8q2820q')); select * from PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------SQL_ID bh01rt8q2820q -------------------SELECT d.setid, d.deptid, d.descr, n.emplid, n.name FROM ps_dept_Tbl d, ps_names n WHERE d.effdt = ( SELECT MAX(d1.effdt) FROM ps_dept_tbl d1 WHERE d1.setid = d.setid AND d1.deptid = d.deptid AND d1.effdt <= SYSDATE ) AND d.eff_status = 'A' AND n.emplid = d.manager_id Plan hash value: 454993881 -------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 13 (100)| | | 1 | NESTED LOOPS | | 2 | 176 | 13 (16)| 00:00:01 | | 2 | HASH JOIN | | 1 | 65 | 11 (19)| 00:00:01 | | 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 330 | 14850 | 6 (0)| 00:00:01 | | 4 | VIEW | VW_SQ_1 | 660 | 13200 | 4 (25)| 00:00:01 | | 5 | HASH GROUP BY | | 660 | 13860 | 4 (25)| 00:00:01 | | 6 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 660 | 13860 | 3 (0)| 00:00:01 | | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 2 | 46 | 2 (0)| 00:00:01 | | 8 | INDEX RANGE SCAN | PS_NAMES | 2 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------------- DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 55 Multiple Execution plans SQL_ID bxu9sk3q91trn -------------------INSERT INTO TMP_ACTSEARCH1 (ACTIVITY_PK) SELECT ACT.ACTIVITY_PK FROM TBL_TMX_ACTIVITY ACT WHERE CONTAINS(ACT.ACTIVITYDESC, :B1 ) > 0 Plan hash value: 2274164979 -------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------| 0 | INSERT STATEMENT | | | | 379K(100)| | | 1 | TABLE ACCESS FULL| TBL_TMX_ACTIVITY | 1 | 74 | 379K (8)| 00:00:30 | -------------------------------------------------------------------------------------SQL_ID bxu9sk3q91trn -------------------INSERT INTO TMP_ACTSEARCH1 (ACTIVITY_PK) SELECT ACT.ACTIVITY_PK FROM TBL_TMX_ACTIVITY ACT WHERE CONTAINS(ACT.ACTIVITYDESC, :B1 ) > 0 Plan hash value: 4216380757 -------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| -------------------------------------------------------------------------------------| 0 | INSERT STATEMENT | | | | 1 (100)| | 1 | TABLE ACCESS BY INDEX ROWID| TBL_TMX_ACTIVITY | 1 | 73 | 0 (0)| | 2 | DOMAIN INDEX | FT_TABLE_RAJLCU1R | | | 0 (0)| -------------------------------------------------------------------------------------- DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 56 DBMS_XPLAN.DISPLAY_SQLSET • Displays execution plan of a statement in a tuning set. – It is licensed as a part of Diagnostic Pack or Tuning Pack DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 57 DBMS_XPLAN.DISPLAY_SQLSET • Usage DBMS_XPLAN.DISPLAY_SQLSET( sqlset_name IN VARCHAR2, sql_id IN VARCHAR2, plan_hash_value IN NUMBER NULL, format IN VARCHAR2 'TYPICAL', sqlset_owner IN VARCHAR2 NULL) DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 58 DBMS_XPLAN. DISPLAY_SQL_PLAN_BASELINE • New in Oracle 11g • Displays execution plan of a statement in a SQL base line. – It is licensed as a part of Tuning Pack(?) DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 59 DBMS_XPLAN. DISPLAY_SQL_PLAN_BASELINE • Usage DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE ( sql_handle IN VARCHAR2 := NULL, plan_name IN VARCHAR2 := NULL, format IN VARCHAR2 := 'TYPICAL') DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 60 What is Wrong with this plan? ---------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time ---------------------------------------------------------------------------------------------------| 1 | NESTED LOOPS | | 1 | 2 | 13 (16)| 65 |00:00:00.06 |* 2 | HASH JOIN | | 1 | 1 | 11 (19)| 618 |00:00:00.04 |* 3 | TABLE ACCESS FULL | PS_DEPT_TBL | 1 | 330 | 6 (0)| 658 |00:00:00.01 | 4 | VIEW | VW_SQ_1 | 1 | 660 | 4 (25)| 620 |00:00:00.02 | 5 | HASH GROUP BY | | 1 | 660 | 4 (25)| 620 |00:00:00.01 |* 6 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 1 | 660 | 3 (0)| 660 |00:00:00.01 | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 618 | 2 | 2 (0)| 65 |00:00:00.02 |* 8 | INDEX RANGE SCAN | PS_NAMES | 618 | 2 | 1 (0)| 65 |00:00:00.01 ---------------------------------------------------------------------------------------------------- | Buffers | | | | | | | | | 793 | 40 | 17 | 17 | 691 Predicate Information (identified by operation id): --------------------------------------------------2 - access("D"."EFFDT"="VW_COL_1" AND SYS_OP_DESCEND("D"."EFFDT")=SYS_OP_DESCEND( "VW_COL_1") AND "SETID"="D"."SETID" AND "DEPTID"="D"."DEPTID") 3 - filter("D"."EFF_STATUS"='A') 6 - filter((SYS_OP_UNDESCEND("D1"."SYS_NC00051$")<=SYSDATE@! AND "D1"."SYS_NC00051$">=SYS_OP_DESCEND(SYSDATE@!))) 8 - access("N"."EMPLID"="D"."MANAGER_ID") DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 61 Skewed distribution of Data SELECT eff_status, count(*) FROM ps_dept_tbl GROUP BY eff_status EFF COUNT(*) --- ---------I 2 A 658 DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 62 Collect Stats with Histograms • This is the default option in 10g begin sys.dbms_stats.gather_table_stats (ownname=>'SYSADM' ,tabname=>'PS_DEPT_TBL' ,estimate_percent=>DBMS_STATS.AUTO_SAMPLE_SIZE ,method_opt=>'FOR ALL COLUMNS SIZE AUTO' ,cascade=>TRUE); end; / DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 63 Any Better? ---------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | Cost (%CPU)| A-Rows | A-Time ---------------------------------------------------------------------------------------------------| 1 | NESTED LOOPS | | 1 | 11 | 21 (10)| 65 |00:00:00.06 |* 2 | HASH JOIN | | 1 | 5 | 11 (19)| 618 |00:00:00.04 | 3 | VIEW | VW_SQ_1 | 1 | 660 | 4 (25)| 620 |00:00:00.01 | 4 | HASH GROUP BY | | 1 | 660 | 4 (25)| 620 |00:00:00.01 |* 5 | INDEX FAST FULL SCAN | PS1DEPT_TBL | 1 | 660 | 3 (0)| 660 |00:00:00.01 |* 6 | TABLE ACCESS FULL | PS_DEPT_TBL | 1 | 658 | 6 (0)| 658 |00:00:00.01 | 7 | TABLE ACCESS BY INDEX ROWID| PS_NAMES | 618 | 2 | 2 (0)| 65 |00:00:00.02 |* 8 | INDEX RANGE SCAN | PS_NAMES | 618 | 2 | 1 (0)| 65 |00:00:00.01 ---------------------------------------------------------------------------------------------------- | Buffers | | | | | | | | | 823 70 17 17 691 Predicate Information (identified by operation id): --------------------------------------------------2 - access("D"."EFFDT"="VW_COL_1" AND SYS_OP_DESCEND("D"."EFFDT")=SYS_OP_DESCEND("VW_COL_1" ) AND "SETID"="D"."SETID" AND "DEPTID"="D"."DEPTID") 5 - filter((SYS_OP_UNDESCEND("D1"."SYS_NC00051$")<=SYSDATE@! AND "D1"."SYS_NC00051$">=SYS_OP_DESCEND(SYSDATE@!))) 6 - filter("D"."EFF_STATUS"='A') 8 - access("N"."EMPLID"="D"."MANAGER_ID") DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 64 | | | | The data is skewed • 37 setids • 435 departments • 37 distinct managers • 1.06 rows per setid & deptid • 19 distinct effective dates. DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 65 Acknowledgements • 10g/11g DBMS_XPLAN – Carol Dacko, University of Michigan • Collaborate 08 Conference presentation – Blog to be launched soon • Rob van Wijk – http://rwijk.blogspot.com/2008/03/dbmsxplandi splaycursor.html DBMS_XPLAN UKOUG2008 ©www.go-faster.co.uk 78 Questions? Obtaining and Interpreting Execution Plans using DBMS_XPLAN David Kurtz Go-Faster Consultancy Ltd. david.kurtz@go-faster.co.uk www.go-faster.co.uk