101 Ways to get SQL Execution Plan. What is the best option to use?
description
Transcript of 101 Ways to get SQL Execution Plan. What is the best option to use?
101 Ways to get SQL Execution Plan. What is the best option to use?
By:
Paul Guerin (Originenergy),
Serge Stadnichenko (Originenergy),
Konrad Dear (Telstra),
Yury Velikanov (Pythian),
& All of you
Introductions
Typical responses to poor performance:
"We need to buy faster hardware!!!""Someone has been dropping indexes!!!""We need to gather stats on the whole database every 5 minutes!!!""Lets create more materialised views!!!“"We develop the application for optimal performance!!!“"Lets use partitioning option!!!""Lets use parllel option!!!"
Inefficient execution plans lead to poor performance and poor scalability....
Few words about - "What is an execution plan?“
Execution plans
> AUTOTRACE (SQL*Plus)> EXPLAN PLAN FOR & DBMS_XPLAN> SQL TRACE aka event 10046> event 10053> Tanel's Dtrace method> V$SQL_PLAN & DBMS_XPLAN.DISPLAY_CURSOR
> SQLT (SQLTXPLAIN) tool from Oracle Support
Execution plans - SET AUTOTRACE – the simplest option
19:38:52 SYSTEM:MEGA> set autotrace helpmefindparametersUsage: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]]
[STAT[ISTICS]]
SET AUTOTRACE ON<statement>;SET AUTOTRACE OFF
21:14:15 IMTDB:SYSTEM> set autotrace on 21:15:29 IMTDB:SYSTEM> select id from t1 t where n1 > 0; ID ---------- 1 2 3 4 ... 998 999 1000 1000 rows selected. Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1000 Bytes=7000) 1 0 TABLE ACCESS (FULL) OF 'T1' (Cost=4 Card=1000 Bytes=7000) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 85 consistent gets 0 physical reads 0 redo size 8516 bytes sent via SQL*Net to client 706 bytes received via SQL*Net from client 68 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1000 rows processed 21:17:47 IMTDB:SYSTEM>
21:27:26 SYSTEM:MEGA> set autotrace on 21:27:48 SYSTEM:MEGA> select id from t1 t where n1 > 0; ID ---------- 1 2 3 4 ... 998 999 1000 1000 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 3617692013 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1000 | 7000 | 6 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T1 | 1000 | 7000 | 6 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("N1">0) Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 85 consistent gets 0 physical reads 0 redo size 11113 bytes sent via SQL*Net to client 1137 bytes received via SQL*Net from client 68 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1000 rows processed 21:28:37 SYSTEM:MEGA>
Execution plans - SET AUTOTRACE – the simplest option
+ It is most probably the simplest possibe option+ Oracle executes an SQL (true execution plan for given session)+ Oracle executes an SQL (statistics are reflected)
- Oracle executes an SQL (results are reflected, what is thousands rows?)
SET AUTOTRACE TRACEONLY
- Oracle executes an SQL (results are fetched to client side)- Oracle executes an SQL (what if it takes hours before is starts
fetching?)- It doens't provide advantacges that other options have
SET AUTOTRACE ON EXPLAINSET AUTOTRACE ON STATISTICS
To use this feature, you must create a PLAN_TABLE table in your schema and then have the PLUSTRACE role granted to you.
@$ORACLE_HOME/rdbms/admin/utlxplan.sql@$ORACLE_HOME/sqlplus/admin/plustrce.sql
Execution plans - EXPLAIN PLAN FOR – plan w/t execution
-- No statement execution, displays predicted plan onlyEXPLAIN PLAN FOR <statement>;SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
21:51:00 IMTDB:SYSTEM> explain plan for select id from t1 t where n1 > 0; Explained. 21:51:04 IMTDB:SYSTEM> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------- -------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1000 | 7000 | 4 | |* 1 | TABLE ACCESS FULL | T1 | 1000 | 7000 | 4 | -------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("T"."N1">0) Note: cpu costing is off 14 rows selected. 21:51:08 IMTDB:SYSTEM>
PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------------------------- Plan hash value: 3739423728 ------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------------- ------------------- | 0 | SELECT STATEMENT | | 1 | 74 | | 34309 (1)|305:38:23 | | 1 | SORT AGGREGATE | | 1 | 74 | | | | | 2 | NESTED LOOPS SEMI | | 2768 | 200K| | 34309 (1)|305:38:23 | | 3 | NESTED LOOPS | | 2768 | 173K| | 28773 (1)|256:19:22 | |* 4 | HASH JOIN | | 521 | 22924 | | 26777 (1)|238:32:29 | | 5 | VIEW | | 499 | 4491 | | 4139 (1)| 36:52:20 | |* 6 | COUNT STOPKEY | | | | | | | | 7 | VIEW | | 255K| 2243K| | 4139 (1)| 36:52:20 | |* 8 | SORT ORDER BY STOPKEY | | 255K| 4736K| 8048K| 4139 (1)| 36:52:20 | |* 9 | TABLE ACCESS FULL | PATIENT_VISIT | 255K| 4736K| | 1618 (0)| 14:24:50 | |* 10 | HASH JOIN RIGHT SEMI | | 292K| 9M| 6416K| 22638 (1)|201:39:53 | |* 11 | TABLE ACCESS FULL | LAB_RESULT_FILE_UPLOAD | 285K| 3068K| | 8781 (0)| 78:13:30 | |* 12 | TABLE ACCESS FULL | STUDY_INV_PATIENT_VISIT_STAGE | 1545K| 35M| | 10655 (0)| 94:55:11 | |* 13 | TABLE ACCESS BY INDEX ROWID| TEST_RESULT_STAGE | 5 | 100 | | 4 (0)| 00:02:09 | |* 14 | INDEX RANGE SCAN | IDX_TRS_PF04 | 6 | | | 3 (0)| 00:01:37 | |* 15 | TABLE ACCESS BY INDEX ROWID | TEST_ORDER | 7739K| 73M| | 2 (0)| 00:01:05 | |* 16 | INDEX UNIQUE SCAN | TEST_ORDER_PK | 1 | | | 1 (0)| 00:00:33 | ------------------------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("SIPVS"."KIT_BARCODE_ID"="KITS_AVAILABLE"."KIT_BARCODE_ID") 6 - filter(ROWNUM<500) 8 - filter(ROWNUM<500) 9 - filter("FINAL_REPORT_DATE" IS NOT NULL AND "ACTIVE"=10) 10 - access("LRFU"."UPLOAD_ID"="SIPVS"."UPLOAD_ID") 11 - filter("LRFU"."LAB_ID"=10034) 12 - filter("SIPVS"."KIT_BARCODE_ID" IS NOT NULL AND "SIPVS"."ACTIVE"=10) 13 - filter("TRS"."TEST_ORDER_ID" IS NOT NULL) 14 - access("SIPVS"."STDINV_PATIENT_VST_STAGE_NF_ID"="TRS"."STDINV_PATIENT_VST_STAGE_NF_ID" AND "TRS"."RESULT_STATUS"=4 AND "TRS"."ACTIVE"=10) filter("TRS"."ACTIVE"=10) 15 - filter("ACTIVE"=10) 16 - access("TOR"."TEST_ORDER_ID"="TRS"."TEST_ORDER_ID") 40 rows selected.
Execution plans - EXPLAIN PLAN FOR – plan w/t execution
+ It retrives executiion plan witout an SQL execution+ It shows predicates for each step (access/filer)+ It reflects prallel execution and partitioning related infromation
automagicly+ It gives you some Hints about the execution (Note: cpu costing is off)
- Oracle makes assumptions on bind variables data types (wrong execution plan)
Execution plans - EXPLAIN PLAN FOR – plan w/t execution
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);
format
Controls the level of details for the plan. It accepts four values:
* BASIC: Displays the minimum information in the plan—the operation ID, the operation name and its option.
* TYPICAL: This is the default. Displays the most relevant information in the plan (operation id, name and option, #rows, #bytes and optimizer cost). Pruning, parallel and predicate information are only displayed when applicable. Excludes only PROJECTION, ALIAS and REMOTE SQL information (see below).
* SERIAL: Like TYPICAL except that the parallel information is not displayed, even if the plan executes in parallel.
* ALL: Maximum user level. Includes information displayed with the TYPICAL level with additional information (PROJECTION, ALIAS and information about REMOTE SQL if the operation is distributed).
21:50:30 IMTDB:prodds2> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null,null,'BASIC')); PLAN_TABLE_OUTPUT ----------------------------------------------------------------------------------------- Plan hash value: 3739423728 ------------------------------------------------------------------------ | Id | Operation | Name | ------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | | 1 | SORT AGGREGATE | | | 2 | NESTED LOOPS SEMI | | | 3 | NESTED LOOPS | | | 4 | HASH JOIN | | | 5 | VIEW | | | 6 | COUNT STOPKEY | | | 7 | VIEW | | | 8 | SORT ORDER BY STOPKEY | | | 9 | TABLE ACCESS FULL | PATIENT_VISIT | | 10 | HASH JOIN RIGHT SEMI | | | 11 | TABLE ACCESS FULL | LAB_RESULT_FILE_UPLOAD | | 12 | TABLE ACCESS FULL | STUDY_INV_PATIENT_VISIT_STAGE | | 13 | TABLE ACCESS BY INDEX ROWID| TEST_RESULT_STAGE | | 14 | INDEX RANGE SCAN | IDX_TRS_PF04 | | 15 | TABLE ACCESS BY INDEX ROWID | TEST_ORDER | | 16 | INDEX UNIQUE SCAN | TEST_ORDER_PK | ------------------------------------------------------------------------ 23 rows selected. 22:27:03 IMTDB:prodds2>
22:29:16 IMTDB:prodds2> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null,null,'ALL')); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------------------------------------------------------ - Plan hash value: 3739423728 ------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 74 | | 34309 (1)|305:38:23 | | 1 | SORT AGGREGATE | | 1 | 74 | | | | | 2 | NESTED LOOPS SEMI | | 2768 | 200K| | 34309 (1)|305:38:23 | | 3 | NESTED LOOPS | | 2768 | 173K| | 28773 (1)|256:19:22 | |* 4 | HASH JOIN | | 521 | 22924 | | 26777 (1)|238:32:29 | | 5 | VIEW | | 499 | 4491 | | 4139 (1)| 36:52:20 | |* 6 | COUNT STOPKEY | | | | | | | | 7 | VIEW | | 255K| 2243K| | 4139 (1)| 36:52:20 | |* 8 | SORT ORDER BY STOPKEY | | 255K| 4736K| 8048K| 4139 (1)| 36:52:20 | |* 9 | TABLE ACCESS FULL | PATIENT_VISIT | 255K| 4736K| | 1618 (0)| 14:24:50 | |* 10 | HASH JOIN RIGHT SEMI | | 292K| 9M| 6416K| 22638 (1)|201:39:53 | |* 11 | TABLE ACCESS FULL | LAB_RESULT_FILE_UPLOAD | 285K| 3068K| | 8781 (0)| 78:13:30 | |* 12 | TABLE ACCESS FULL | STUDY_INV_PATIENT_VISIT_STAGE | 1545K| 35M| | 10655 (0)| 94:55:11 | |* 13 | TABLE ACCESS BY INDEX ROWID| TEST_RESULT_STAGE | 5 | 100 | | 4 (0)| 00:02:09 | |* 14 | INDEX RANGE SCAN | IDX_TRS_PF04 | 6 | | | 3 (0)| 00:01:37 | |* 15 | TABLE ACCESS BY INDEX ROWID | TEST_ORDER | 7739K| 73M| | 2 (0)| 00:01:05 | |* 16 | INDEX UNIQUE SCAN | TEST_ORDER_PK | 1 | | | 1 (0)| 00:00:33 | ------------------------------------------------------------------------------------------------------------------------ Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$F2CA64D4 5 - SEL$2 / KITS_AVAILABLE@SEL$1 6 - SEL$2 7 - SEL$3 / from$_subquery$_004@SEL$2 8 - SEL$3 9 - SEL$3 / PATIENT_VISIT@SEL$3 11 - SEL$F2CA64D4 / LRFU@SEL$5 12 - SEL$F2CA64D4 / SIPVS@SEL$1 13 - SEL$F2CA64D4 / TRS@SEL$1 14 - SEL$F2CA64D4 / TRS@SEL$1 15 - SEL$F2CA64D4 / TOR@SEL$4 16 - SEL$F2CA64D4 / TOR@SEL$4 Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("SIPVS"."KIT_BARCODE_ID"="KITS_AVAILABLE"."KIT_BARCODE_ID") 6 - filter(ROWNUM<500) 8 - filter(ROWNUM<500) 9 - filter("FINAL_REPORT_DATE" IS NOT NULL AND "ACTIVE"=10) 10 - access("LRFU"."UPLOAD_ID"="SIPVS"."UPLOAD_ID") 11 - filter("LRFU"."LAB_ID"=10034) 12 - filter("SIPVS"."KIT_BARCODE_ID" IS NOT NULL AND "SIPVS"."ACTIVE"=10) 13 - filter("TRS"."TEST_ORDER_ID" IS NOT NULL) 14 - access("SIPVS"."STDINV_PATIENT_VST_STAGE_NF_ID"="TRS"."STDINV_PATIENT_VST_STAGE_NF_ID" AND "TRS"."RESULT_STATUS"=4 AND "TRS"."ACTIVE"=10) filter("TRS"."ACTIVE"=10) 15 - filter("ACTIVE"=10) 16 - access("TOR"."TEST_ORDER_ID"="TRS"."TEST_ORDER_ID") Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 2 - (#keys=0) 3 - (#keys=0) "TRS"."TEST_ORDER_ID"[NUMBER,22] 4 - (#keys=1) "SIPVS"."STDINV_PATIENT_VST_STAGE_NF_ID"[NUMBER,22] 5 - "KITS_AVAILABLE"."KIT_BARCODE_ID"[VARCHAR2,30] 6 - "KIT_BARCODE_ID"[VARCHAR2,30] 7 - "KIT_BARCODE_ID"[VARCHAR2,30] 8 - (#keys=1) INTERNAL_FUNCTION("FINAL_REPORT_DATE")[7], "KIT_BARCODE_ID"[VARCHAR2,30] 9 - "KIT_BARCODE_ID"[VARCHAR2,30], "FINAL_REPORT_DATE"[DATE,7]
Execution plans - SET AUTOTRACE – might lie !
REF: Jonathan Lewis
http://jonathanlewis.wordpress.com/testing-autotrace/
set autotrace traceonly explain – doens’t execute an SQL
Konrad
> SQL TRACE aka event 10046
> event 10053
> Tanel's Dtrace method
Execution plans - v$sql_plan
Determine the session and cursorv$session, v$sql: hash_value, address, child_number (9i)
sql_id, child_number (11g)
Session activity gives clues to what is in the execution plan…
v$session_event: db file sequential read, db file scattered readv$session_wait:v$session_longops: Table Scan
Execution plans - v$sql_plan
Actual execution plan (9i)
truncate table plan_table;
-- Following is equivalent to EXPLAIN PLAN FOR <statement>insert into plan_table (statement_id, timestamp, OPERATION, OPTIONS, OBJECT_NODE,
OBJECT_OWNER, OBJECT_NAME, OPTIMIZER, ID, PARENT_ID, POSITION, SEARCH_COLUMNS, COST, CARDINALITY, BYTES, OTHER_TAG, PARTITION_START, PARTITION_STOP, PARTITION_ID, OTHER, DISTRIBUTION, CPU_COST, IO_COST, TEMP_SPACE, ACCESS_PREDICATES, FILTER_PREDICATES)
select 0, sysdate, OPERATION, OPTIONS, OBJECT_NODE, OBJECT_OWNER, OBJECT_NAME, OPTIMIZER, ID, PARENT_ID, POSITION, SEARCH_COLUMNS, COST, CARDINALITY, BYTES,
OTHER_TAG, PARTITION_START, PARTITION_STOP, PARTITION_ID, OTHER, DISTRIBUTION, CPU_COST, IO_COST, TEMP_SPACE, ACCESS_PREDICATES, FILTER_PREDICATES
from v$sql_planwhere hash_value=&hsh and address='&add' and child_number=&chld;
-- Displays the actual plan instead of the predicted planselect * from table(dbms_xplan.display);
Execution plans - v$sql_plan
Actual execution plan (10g/11g)
-- execution plan for last cursor of sessionSELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR);
-- execution plan for a cached cursor (need sql_id + child_number from v$sql)SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR('<sql_id>',<child#>));
-- execution plan for an AWR cursor (need sql_id from DBA_HIST_SQLTEXT)SELECT * FROM table(DBMS_XPLAN.DISPLAY_AWR('<sql_id>'));
-- Plan related dynamic viewsV$SQL_PLANV$SQL_PLAN_MONITOR Plan level monitoring statistics.V$SQL_BIND_CAPTURE Bind variables used for a cursor.V$SQL_BIND_DATA As above, except for current session.
Execution plans
11g features:
DBMS_SQLTUNE.REPORT_SQL_MONITOR();Create a report that can include explain plan and binds.
SQL Plan BaselinesStorage of past plans that are considered efficient.
Execution plans - SQLT (SQLTXPLAIN) tool from Oracle Support
DEMO
SQLT (SQLTXPLAIN) –
Tool that helps to diagnose SQL statements performing poorly [ID 215187.1]
+ It is most complete and comprehansive option+ Support 9.2.0.1 to 11.2.0.1 RDBMS versions+ Can use many different sources as input
- Needs additional instaltion in the production DB+ Install in totaly isolated schema (SQLTXPLAIN)- A report generating process is relativly complex
(as application owner with additional privileges, multiple stages)- Sometimes generating process is resources intensive