目录
查看执行计划的方法
1、Explain Plan For SQL
1.1 查看plan_table
1.2 解析SQL执行计划
1.3 查看执行计划
2、SQLPLUS AUTOTRACE
2.1 查看plan_table
2.2 查看SQL执行计划
3、SQL TRACE
3.1 执行SQL TRACE
3.2 查看trc文件中的执行计划
4、V$SQL和V$SQL_PLAN
4.1 session2执行SQL:
4.2 session1查看SQL_ID
4.3 通过sql_id查看执行计划
5、SQL Monitor
6、其他第三方工具
最详细的执行计划
通过sql_id查执行计划
session执行SQL:
查找出SQL_ID
通过sql_id查看执行计划
不通过sql_id查执行计划
statistics_level设为ALL
查看执行计划的方法
在简单的执行计划中,执行计划的列分别有:Id,Operation,Name,Rows,Bytes,Cost (%CPU),Time
Id,Operation,Name——这三项是每个执行计划中都有的
Rows,Bytes,Cost (%CPU),Time——这四项是Oracle预估的值
Rows:指Oracle预估这一步返回多少行记录
Bytes:指Rows返回记录占用的空间
Cost (%CPU):指Oracle内部计算的一个代价
Time:指Oracle预估的耗时。
正常情况下,Rows,Bytes,Cost (%CPU),Time这四个值只是估算值,根据统计信息,主机性能以及一些指标计算出来的、内部认为的、估算出来的值,这些值可能是准确的,也可能是不准确的。可以作为参考,但是不能作为依据。
1、Explain Plan For SQL
实际执行SQL语句,生成的计划未必是真实执行的计划
必须要有plan_table
1.1 查看plan_table
SQL> desc plan_table Name Null? Type ----------------------------------------- -------- ---------------------------- STATEMENT_ID VARCHAR2(30) PLAN_ID NUMBER TIMESTAMP DATE REMARKS VARCHAR2(4000) OPERATION VARCHAR2(30) OPTIONS VARCHAR2(255) OBJECT_NODE VARCHAR2(128) OBJECT_OWNER VARCHAR2(30) OBJECT_NAME VARCHAR2(30) OBJECT_ALIAS VARCHAR2(65) OBJECT_INSTANCE NUMBER(38) OBJECT_TYPE VARCHAR2(30) OPTIMIZER VARCHAR2(255) SEARCH_COLUMNS NUMBER ID NUMBER(38) PARENT_ID NUMBER(38) DEPTH NUMBER(38) POSITION NUMBER(38) COST NUMBER(38) CARDINALITY NUMBER(38) BYTES NUMBER(38) OTHER_TAG VARCHAR2(255) PARTITION_START VARCHAR2(255) PARTITION_STOP VARCHAR2(255) PARTITION_ID NUMBER(38) OTHER LONG OTHER_XML CLOB DISTRIBUTION VARCHAR2(30) CPU_COST NUMBER(38) IO_COST NUMBER(38) TEMP_SPACE NUMBER(38) ACCESS_PREDICATES VARCHAR2(4000) FILTER_PREDICATES VARCHAR2(4000) PROJECTION VARCHAR2(4000) TIME NUMBER(38) QBLOCK_NAME VARCHAR2(30) SQL> |
1.2 解析SQL执行计划
SQL> explain plan for select * from liyuper where employee_id=100; Explained. SQL> |
1.3 查看执行计划
SQL> select * from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Plan hash value: 2406067938 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 69 | 2 (0) | 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| LIYUPER | 1 | 69 | 2 (0) | 00:00:01 | |* 2 | INDEX RANGE SCAN | I_T2_ID | 1 | | 1 (0) | 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID"=100) 14 rows selected. SQL> |
2、SQLPLUS AUTOTRACE
除set autotrace traceonly explain外均实际执行SQL,但仍未必是真实计划
必须有plan_table
2.1 查看plan_table
SQL> desc plan_table Name Null? Type ----------------------------------------- -------- ---------------------------- STATEMENT_ID VARCHAR2(30) PLAN_ID NUMBER TIMESTAMP DATE REMARKS VARCHAR2(4000) OPERATION VARCHAR2(30) OPTIONS VARCHAR2(255) OBJECT_NODE VARCHAR2(128) OBJECT_OWNER VARCHAR2(30) OBJECT_NAME VARCHAR2(30) OBJECT_ALIAS VARCHAR2(65) OBJECT_INSTANCE NUMBER(38) OBJECT_TYPE VARCHAR2(30) OPTIMIZER VARCHAR2(255) SEARCH_COLUMNS NUMBER ID NUMBER(38) PARENT_ID NUMBER(38) DEPTH NUMBER(38) POSITION NUMBER(38) COST NUMBER(38) CARDINALITY NUMBER(38) BYTES NUMBER(38) OTHER_TAG VARCHAR2(255) PARTITION_START VARCHAR2(255) PARTITION_STOP VARCHAR2(255) PARTITION_ID NUMBER(38) OTHER LONG OTHER_XML CLOB DISTRIBUTION VARCHAR2(30) CPU_COST NUMBER(38) IO_COST NUMBER(38) TEMP_SPACE NUMBER(38) ACCESS_PREDICATES VARCHAR2(4000) FILTER_PREDICATES VARCHAR2(4000) PROJECTION VARCHAR2(4000) TIME NUMBER(38) QBLOCK_NAME VARCHAR2(30) SQL> |
2.2 查看SQL执行计划
Usage: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
SQL> set autotrace on SQL> select EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY from liyuper where employee_id=100; EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY ----------- -------------------- ------------------------- ---------- 100 Steven King 200 Execution Plan ---------------------------------------------------------- Plan hash value: 2406067938 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 23 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| LIYUPER | 1 | 23 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | I_T2_ID | 1 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID"=100) Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 3 consistent gets 0 physical reads 0 redo size 755 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> |
3、SQL TRACE
需要启用10046或者SQL TRACE
一般用tkprof看得更清楚些,当然10046里本身也有执行计划信息
3.1 执行SQL TRACE
SQL> alter session set sql_trace=true; Session altered. SQL> select EMPLOYEE_ID,FIRST_NAME,LAST_NAME,SALARY from liyuper where employee_id=100; EMPLOYEE_ID FIRST_NAME LAST_NAME SALARY ----------- -------------------- ------------------------- ---------- 100 Steven King 200 SQL> alter session set sql_trace=false; Session altered. SQL> show parameter user_dump NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ user_dump_dest string /u01/app/oracle/diag/rdbms/lyp db/lypdb/trace SQL> Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production With the Partitioning, OLAP, Data Mining and Real Application Testing options [oracle@lypos ~]$ |
3.2 查看trc文件中的执行计划
[oracle@lypos ~]$ cd /u01/app/oracle/diag/rdbms/lypdb/lypdb/trace [oracle@lypos trace]$ ls -rlt |head total 152 -rw-r-----. 1 oracle oinstall 142144 Dec 10 11:40 alert_lypdb.log -rw-r----- 1 oracle oinstall 95 Dec 10 15:36 lypdb_ora_4031.trm -rw-r----- 1 oracle oinstall 2872 Dec 10 15:36 lypdb_ora_4031.trc [oracle@lypos trace]$ tkprof lypdb_ora_4031.trc lypdb_ora_4031.tk.log TKPROF: Release 11.2.0.4.0 - Development on Mon Dec 10 15:37:14 2018 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. [oracle@lypos trace]$ cat lypdb_ora_4031.tk.log TKPROF: Release 11.2.0.4.0 - Development on Mon Dec 10 15:37:14 2018 Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved. Trace file: lypdb_ora_4031.trc Sort options: default *********************************省略*********************************************** Optimizer mode: ALL_ROWS Parsing user id: 85 Number of plan statistics captured: 1 Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- --------------------------------------------------- 1 1 1 TABLE ACCESS BY INDEX ROWID LIYUPER (cr=3 pr=0 pw=0 time=161 us cost=2 size=23 card=1) 1 1 1 INDEX RANGE SCAN I_T2_ID (cr=2 pr=0 pw=0 time=58 us cost=1 size=0 card=1)(object id 88098) ******************************************************************************** SQL ID: aam2chsgpj7mb Plan Hash: 0 alter session set sql_trace=false ***********************************省略********************************************* Trace file: lypdb_ora_4031.trc Trace file compatibility: 11.1.0.7 Sort options: default 1 session in tracefile. 3 user SQL statements in trace file. 0 internal SQL statements in trace file. 3 SQL statements in trace file. 3 unique SQL statements in trace file. 55 lines in trace file. 18 elapsed seconds in trace file. [oracle@lypos trace]$ |
4、V$SQL和V$SQL_PLAN
可以查询到多个子游标的计划信息了,但是看起来比较费劲
4.1 session2执行SQL:
SQL> conn liyuper/liyuper; Connected. SQL> select count(*) from dba_objects,dba_objects,dba_objects,dba_objects; |
4.2 session1查看SQL_ID
SQL> select SQL_ID,LAST_CALL_ET,PROGRAM,USERNAME from v$session where type !='BACKGROUND' and status = 'ACTIVE'; SQL_ID LAST_CALL_ET PROGRAM USERNAME ------------- ------------ ------------------------------------------------ ------------------------------ 6h5xm74kx8n9k 0 sqlplus@lypos (TNS V1-V3) LIYUPER 1pw97a04vpt4h 96 sqlplus@lypos (TNS V1-V3) LIYUPER SQL> |
4.3 通过sql_id查看执行计划
SQL> select * from table(dbms_xplan.display_cursor('1pw97a04vpt4h',null)); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 1pw97a04vpt4h, child number 0 ------------------------------------- select count(*) from dba_objects,dba_objects,dba_objects,dba_objects Plan hash value: 198298237 -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 190P(100)| | | 1 | SORT AGGREGATE | | 1 | | | | | 2 | MERGE JOIN CARTESIAN | | 18E| | 190P (1)|999:59:59 | | 3 | MERGE JOIN CARTESIAN | | 644T| | 2208G (1)|999:59:59 | | 4 | MERGE JOIN CARTESIAN | | 7461M| | 25M (1)| 85:13:08 | | 5 | VIEW | DBA_OBJECTS | 86382 | | 296 (2)| 00:00:04 | | 6 | UNION-ALL | | | | | | |* 7 | FILTER | | | | | | |* 8 | HASH JOIN | | 86381 | 9279K| 296 (2)| 00:00:04 | | 9 | INDEX FULL SCAN | I_USER2 | 89 | 356 | 1 (0)| 00:00:01 | |* 10 | HASH JOIN | | 86381 | 8941K| 295 (2)| 00:00:04 | | 11 | INDEX FULL SCAN | I_USER2 | 89 | 1958 | 1 (0)| 00:00:01 | |* 12 | TABLE ACCESS FULL | OBJ$ | 86381 | 7085K| 293 (1)| 00:00:04 | | 13 | NESTED LOOPS | | 1 | 29 | 2 (0)| 00:00:01 | |* 14 | INDEX SKIP SCAN | I_USER2 | 1 | 20 | 1 (0)| 00:00:01 | |* 15 | INDEX RANGE SCAN | I_OBJ4 | 1 | 9 | 1 (0)| 00:00:01 | | 16 | NESTED LOOPS | | 1 | 17 | 0 (0)| | | 17 | INDEX FULL SCAN | I_LINK1 | 1 | 13 | 0 (0)| | | 18 | TABLE ACCESS CLUSTER | USER$ | 1 | 4 | 0 (0)| | |* 19 | INDEX UNIQUE SCAN | I_USER# | 1 | | 0 (0)| | | 20 | BUFFER SORT | | 86382 | | 25M (1)| 85:13:08 | | 21 | VIEW | DBA_OBJECTS | 86382 | | 296 (2)| 00:00:04 | | 22 | UNION-ALL | | | | | | |* 23 | FILTER | | | | | | |* 24 | HASH JOIN | | 86381 | 9279K| 296 (2)| 00:00:04 | | 25 | INDEX FULL SCAN | I_USER2 | 89 | 356 | 1 (0)| 00:00:01 | |* 26 | HASH JOIN | | 86381 | 8941K| 295 (2)| 00:00:04 | | 27 | INDEX FULL SCAN | I_USER2 | 89 | 1958 | 1 (0)| 00:00:01 | |* 28 | TABLE ACCESS FULL | OBJ$ | 86381 | 7085K| 293 (1)| 00:00:04 | | 29 | NESTED LOOPS | | 1 | 29 | 2 (0)| 00:00:01 | |* 30 | INDEX SKIP SCAN | I_USER2 | 1 | 20 | 1 (0)| 00:00:01 | |* 31 | INDEX RANGE SCAN | I_OBJ4 | 1 | 9 | 1 (0)| 00:00:01 | | 32 | NESTED LOOPS | | 1 | 17 | 0 (0)| | | 33 | INDEX FULL SCAN | I_LINK1 | 1 | 13 | 0 (0)| | | 34 | TABLE ACCESS CLUSTER| USER$ | 1 | 4 | 0 (0)| | |* 35 | INDEX UNIQUE SCAN | I_USER# | 1 | | 0 (0)| | | 36 | BUFFER SORT | | 86382 | | 2208G (1)|999:59:59 | | 37 | VIEW | DBA_OBJECTS | 86382 | | 296 (2)| 00:00:04 | | 38 | UNION-ALL | | | | | | |* 39 | FILTER | | | | | | |* 40 | HASH JOIN | | 86381 | 9279K| 296 (2)| 00:00:04 | | 41 | INDEX FULL SCAN | I_USER2 | 89 | 356 | 1 (0)| 00:00:01 | |* 42 | HASH JOIN | | 86381 | 8941K| 295 (2)| 00:00:04 | | 43 | INDEX FULL SCAN | I_USER2 | 89 | 1958 | 1 (0)| 00:00:01 | |* 44 | TABLE ACCESS FULL | OBJ$ | 86381 | 7085K| 293 (1)| 00:00:04 | | 45 | NESTED LOOPS | | 1 | 29 | 2 (0)| 00:00:01 | |* 46 | INDEX SKIP SCAN | I_USER2 | 1 | 20 | 1 (0)| 00:00:01 | |* 47 | INDEX RANGE SCAN | I_OBJ4 | 1 | 9 | 1 (0)| 00:00:01 | | 48 | NESTED LOOPS | | 1 | 17 | 0 (0)| | | 49 | INDEX FULL SCAN | I_LINK1 | 1 | 13 | 0 (0)| | | 50 | TABLE ACCESS CLUSTER | USER$ | 1 | 4 | 0 (0)| | |* 51 | INDEX UNIQUE SCAN | I_USER# | 1 | | 0 (0)| | | 52 | BUFFER SORT | | 86382 | | 190P (1)|999:59:59 | | 53 | VIEW | DBA_OBJECTS | 86382 | | 296 (2)| 00:00:04 | | 54 | UNION-ALL | | | | | | |* 55 | FILTER | | | | | | |* 56 | HASH JOIN | | 86381 | 9279K| 296 (2)| 00:00:04 | | 57 | INDEX FULL SCAN | I_USER2 | 89 | 356 | 1 (0)| 00:00:01 | |* 58 | HASH JOIN | | 86381 | 8941K| 295 (2)| 00:00:04 | | 59 | INDEX FULL SCAN | I_USER2 | 89 | 1958 | 1 (0)| 00:00:01 | |* 60 | TABLE ACCESS FULL | OBJ$ | 86381 | 7085K| 293 (1)| 00:00:04 | | 61 | NESTED LOOPS | | 1 | 29 | 2 (0)| 00:00:01 | |* 62 | INDEX SKIP SCAN | I_USER2 | 1 | 20 | 1 (0)| 00:00:01 | |* 63 | INDEX RANGE SCAN | I_OBJ4 | 1 | 9 | 1 (0)| 00:00:01 | | 64 | NESTED LOOPS | | 1 | 17 | 0 (0)| | | 65 | INDEX FULL SCAN | I_LINK1 | 1 | 13 | 0 (0)| | | 66 | TABLE ACCESS CLUSTER | USER$ | 1 | 4 | 0 (0)| | |* 67 | INDEX UNIQUE SCAN | I_USER# | 1 | | 0 (0)| | -------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 7 - filter((("O"."TYPE#"<>4 AND "O"."TYPE#"<>5 AND "O"."TYPE#"<>7 AND "O"."TYPE#"<>8 AND "O"."TYPE#"<>9 AND "O"."TYPE#"<>11 AND "O"."TYPE#"<>12 AND "O"."TYPE#"<>13 AND "O"."TYPE#"<>14 AND "O"."TYPE#"<>22 AND "O"."TYPE#"<>87 AND "O"."TYPE#"<>88) OR BITAND("U"."SPARE1",16)=0 OR (INTERNAL_FUNCTION("O"."TYPE#") AND ((SYS_CONTEXT('userenv','current_edition_name')='ORA$BASE' AND "U"."TYPE#"<>2) OR ("U"."TYPE#"=2 AND "U"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_ id'))) OR IS NOT NULL)))) 8 - access("O"."SPARE3"="U"."USER#") 10 - access("O"."OWNER#"="U"."USER#") 12 - filter(("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0)) 14 - access("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','curr ent_edition_id'))) filter(("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','cur rent_edition_id')))) 15 - access("O2"."DATAOBJ#"=:B1 AND "O2"."TYPE#"=88 AND "O2"."OWNER#"="U2"."USER#") 19 - access("L"."OWNER#"="U"."USER#") 23 - filter((("O"."TYPE#"<>4 AND "O"."TYPE#"<>5 AND "O"."TYPE#"<>7 AND "O"."TYPE#"<>8 AND "O"."TYPE#"<>9 AND "O"."TYPE#"<>11 AND "O"."TYPE#"<>12 AND "O"."TYPE#"<>13 AND "O"."TYPE#"<>14 AND "O"."TYPE#"<>22 AND "O"."TYPE#"<>87 AND "O"."TYPE#"<>88) OR BITAND("U"."SPARE1",16)=0 OR (INTERNAL_FUNCTION("O"."TYPE#") AND ((SYS_CONTEXT('userenv','current_edition_name')='ORA$BASE' AND "U"."TYPE#"<>2) OR ("U"."TYPE#"=2 AND "U"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_ id'))) OR IS NOT NULL)))) 24 - access("O"."SPARE3"="U"."USER#") 26 - access("O"."OWNER#"="U"."USER#") 28 - filter(("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0)) 30 - access("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','curr ent_edition_id'))) filter(("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','cur rent_edition_id')))) 31 - access("O2"."DATAOBJ#"=:B1 AND "O2"."TYPE#"=88 AND "O2"."OWNER#"="U2"."USER#") 35 - access("L"."OWNER#"="U"."USER#") 39 - filter((("O"."TYPE#"<>4 AND "O"."TYPE#"<>5 AND "O"."TYPE#"<>7 AND "O"."TYPE#"<>8 AND "O"."TYPE#"<>9 AND "O"."TYPE#"<>11 AND "O"."TYPE#"<>12 AND "O"."TYPE#"<>13 AND "O"."TYPE#"<>14 AND "O"."TYPE#"<>22 AND "O"."TYPE#"<>87 AND "O"."TYPE#"<>88) OR BITAND("U"."SPARE1",16)=0 OR (INTERNAL_FUNCTION("O"."TYPE#") AND ((SYS_CONTEXT('userenv','current_edition_name')='ORA$BASE' AND "U"."TYPE#"<>2) OR ("U"."TYPE#"=2 AND "U"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_ id'))) OR IS NOT NULL)))) 40 - access("O"."SPARE3"="U"."USER#") 42 - access("O"."OWNER#"="U"."USER#") 44 - filter(("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0)) 46 - access("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','curr ent_edition_id'))) filter(("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','cur rent_edition_id')))) 47 - access("O2"."DATAOBJ#"=:B1 AND "O2"."TYPE#"=88 AND "O2"."OWNER#"="U2"."USER#") 51 - access("L"."OWNER#"="U"."USER#") 55 - filter((("O"."TYPE#"<>4 AND "O"."TYPE#"<>5 AND "O"."TYPE#"<>7 AND "O"."TYPE#"<>8 AND "O"."TYPE#"<>9 AND "O"."TYPE#"<>11 AND "O"."TYPE#"<>12 AND "O"."TYPE#"<>13 AND "O"."TYPE#"<>14 AND "O"."TYPE#"<>22 AND "O"."TYPE#"<>87 AND "O"."TYPE#"<>88) OR BITAND("U"."SPARE1",16)=0 OR (INTERNAL_FUNCTION("O"."TYPE#") AND ((SYS_CONTEXT('userenv','current_edition_name')='ORA$BASE' AND "U"."TYPE#"<>2) OR ("U"."TYPE#"=2 AND "U"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_ id'))) OR IS NOT NULL)))) 56 - access("O"."SPARE3"="U"."USER#") 58 - access("O"."OWNER#"="U"."USER#") 60 - filter(("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0)) 62 - access("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','curr ent_edition_id'))) filter(("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','cur rent_edition_id')))) 63 - access("O2"."DATAOBJ#"=:B1 AND "O2"."TYPE#"=88 AND "O2"."OWNER#"="U2"."USER#") 67 - access("L"."OWNER#"="U"."USER#") 159 rows selected. SQL> |
5、SQL Monitor
准确显示各个步骤实际执行结果
6、其他第三方工具
注意PL/SQL developer之类工具F5看到的执行计划未必是真实的
这种查看执行计划的原理和本质跟第一种方式是一样的。
最详细的执行计划
通过sql_id查执行计划
一般的执行计划,只能通过cost的大小来看出问题所在的地方。但是这个方法不一定完全正确。
session执行SQL:
SQL> select /*+gather_plan_statistics */ count(*) from dba_objects; COUNT(*) ---------- 86480 SQL> |
查找出SQL_ID
SQL> select sql_id from v$sql where sql_text like 'select /*+gather_plan_statistics */ count(*) from dba_objects'; SQL_ID ------------- c8trdy942j9a9 SQL> |
通过sql_id查看执行计划
如果是同一个会话,可以忽略sql_id,直接执行select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS'));
就会默认的出来刚才执行的SQL的执行计划。(最后展示出来)
SQL> select * from table(dbms_xplan.display_cursor('c8trdy942j9a9',null,'ALLSTATS')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID c8trdy942j9a9, child number 0 ------------------------------------- select /*+gather_plan_statistics */ count(*) from dba_objects Plan hash value: 2509769952 ----------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | O/1/M | ----------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.08 | 1075 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.08 | 1075 | | | | | 2 | VIEW | DBA_OBJECTS | 1 | 86382 | 86435 |00:00:00.25 | 1075 | | | | | 3 | UNION-ALL | | 1 | | 86435 |00:00:00.23 | 1075 | | | | |* 4 | FILTER | | 1 | | 86435 |00:00:00.11 | 1074 | | | | |* 5 | HASH JOIN | | 1 | 86381 | 86435 |00:00:00.08 | 1074 | 2440K| 2440K| 1/0/0| | 6 | INDEX FULL SCAN | I_USER2 | 1 | 89 | 90 |00:00:00.01 | 1 | | | | |* 7 | HASH JOIN | | 1 | 86381 | 86435 |00:00:00.06 | 1073 | 1696K| 1696K| 1/0/0| | 8 | INDEX FULL SCAN | I_USER2 | 1 | 89 | 90 |00:00:00.01 | 1 | | | | |* 9 | TABLE ACCESS FULL | OBJ$ | 1 | 86381 | 86435 |00:00:00.03 | 1072 | | | | | 10 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 | | | | |* 11 | INDEX SKIP SCAN | I_USER2 | 0 | 1 | 0 |00:00:00.01 | 0 | | | | |* 12 | INDEX RANGE SCAN | I_OBJ4 | 0 | 1 | 0 |00:00:00.01 | 0 | | | | | 13 | NESTED LOOPS | | 1 | 1 | 0 |00:00:00.01 | 1 | | | | | 14 | INDEX FULL SCAN | I_LINK1 | 1 | 1 | 0 |00:00:00.01 | 1 | | | | | 15 | TABLE ACCESS CLUSTER| USER$ | 0 | 1 | 0 |00:00:00.01 | 0 | | | | |* 16 | INDEX UNIQUE SCAN | I_USER# | 0 | 1 | 0 |00:00:00.01 | 0 | | | | ----------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter((("O"."TYPE#"<>4 AND "O"."TYPE#"<>5 AND "O"."TYPE#"<>7 AND "O"."TYPE#"<>8 AND "O"."TYPE#"<>9 AND "O"."TYPE#"<>11 AND "O"."TYPE#"<>12 AND "O"."TYPE#"<>13 AND "O"."TYPE#"<>14 AND "O"."TYPE#"<>22 AND "O"."TYPE#"<>87 AND "O"."TYPE#"<>88) OR BITAND("U"."SPARE1",16)=0 OR (INTERNAL_FUNCTION("O"."TYPE#") AND ((SYS_CONTEXT('userenv','current_edition_name')='ORA$BASE' AND "U"."TYPE#"<>2) OR ("U"."TYPE#"=2 AND "U"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_id'))) OR IS NOT NULL)))) 5 - access("O"."SPARE3"="U"."USER#") 7 - access("O"."OWNER#"="U"."USER#") 9 - filter(("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0)) 11 - access("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_id'))) filter(("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_id')))) 12 - access("O2"."DATAOBJ#"=:B1 AND "O2"."TYPE#"=88 AND "O2"."OWNER#"="U2"."USER#") 16 - access("L"."OWNER#"="U"."USER#") 45 rows selected. SQL> |
所以在这里加了一些hint,让他有更准确的执行计划。多了几个新的列:A-Rows(真实返回的行数)、A-Time(准确的耗费时间)、Buffers(逻辑读)
SQL> select count(*) from OBJ$;
COUNT(*)
----------
86440
SQL>
这里可以看到这个86440,是大于上面返回的86535的,原因就是因为前面有个“*”号,下面有条件进行筛选。
SQL> select count(*) from OBJ$ o
2 where (("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND
3 "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0))
4 ;
COUNT(*)
----------
86435
SQL>
这里看起来就一样了。
SQL> set autot on SQL> select count(*) from OBJ$ o 2 where (("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND 3 "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0)) 4 ; COUNT(*) ---------- 86435 Execution Plan ---------------------------------------------------------- Plan hash value: 23986678 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 84 | 293 (1)| 00:00:04 | | 1 | SORT AGGREGATE | | 1 | 84 | | | |* 2 | TABLE ACCESS FULL| OBJ$ | 86381 | 7085K| 293 (1)| 00:00:04 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 1072 consistent gets 0 physical reads 0 redo size 528 bytes sent via SQL*Net to client 520 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> |
这里可以看到逻辑读是1072,对比上面的执行计划显示的1072是一致的。
不通过sql_id查执行计划
同一会话,跳过查询sql_id的步骤:
SQL> select /*+ gather_plan_statistics */ count(*) from dba_objects; COUNT(*) ---------- 86435 SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 86pdr43g2p8fd, child number 0 ------------------------------------- select /*+ gather_plan_statistics */ count(*) from dba_objects Plan hash value: 2509769952 ----------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | O/1/M | ----------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | | 2 |00:00:00.19 | 2150 | | | | | 1 | SORT AGGREGATE | | 2 | 1 | 2 |00:00:00.19 | 2150 | | | | | 2 | VIEW | DBA_OBJECTS | 2 | 86382 | 172K|00:00:00.47 | 2150 | | | | | 3 | UNION-ALL | | 2 | | 172K|00:00:00.41 | 2150 | | | | |* 4 | FILTER | | 2 | | 172K|00:00:00.35 | 2148 | | | | |* 5 | HASH JOIN | | 2 | 86381 | 172K|00:00:00.25 | 2148 | 2440K| 2440K| 2/0/0| | 6 | INDEX FULL SCAN | I_USER2 | 2 | 89 | 180 |00:00:00.01 | 2 | | | | |* 7 | HASH JOIN | | 2 | 86381 | 172K|00:00:00.16 | 2146 | 1696K| 1696K| 2/0/0| | 8 | INDEX FULL SCAN | I_USER2 | 2 | 89 | 180 |00:00:00.01 | 2 | | | | |* 9 | TABLE ACCESS FULL | OBJ$ | 2 | 86381 | 172K|00:00:00.07 | 2144 | | | | | 10 | NESTED LOOPS | | 0 | 1 | 0 |00:00:00.01 | 0 | | | | |* 11 | INDEX SKIP SCAN | I_USER2 | 0 | 1 | 0 |00:00:00.01 | 0 | | | | |* 12 | INDEX RANGE SCAN | I_OBJ4 | 0 | 1 | 0 |00:00:00.01 | 0 | | | | | 13 | NESTED LOOPS | | 2 | 1 | 0 |00:00:00.01 | 2 | | | | | 14 | INDEX FULL SCAN | I_LINK1 | 2 | 1 | 0 |00:00:00.01 | 2 | | | | | 15 | TABLE ACCESS CLUSTER| USER$ | 0 | 1 | 0 |00:00:00.01 | 0 | | | | |* 16 | INDEX UNIQUE SCAN | I_USER# | 0 | 1 | 0 |00:00:00.01 | 0 | | | | ----------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter((("O"."TYPE#"<>4 AND "O"."TYPE#"<>5 AND "O"."TYPE#"<>7 AND "O"."TYPE#"<>8 AND "O"."TYPE#"<>9 AND "O"."TYPE#"<>11 AND "O"."TYPE#"<>12 AND "O"."TYPE#"<>13 AND "O"."TYPE#"<>14 AND "O"."TYPE#"<>22 AND "O"."TYPE#"<>87 AND "O"."TYPE#"<>88) OR BITAND("U"."SPARE1",16)=0 OR (INTERNAL_FUNCTION("O"."TYPE#") AND ((SYS_CONTEXT('userenv','current_edition_name')='ORA$BASE' AND "U"."TYPE#"<>2) OR ("U"."TYPE#"=2 AND "U"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_id'))) OR IS NOT NULL)))) 5 - access("O"."SPARE3"="U"."USER#") 7 - access("O"."OWNER#"="U"."USER#") 9 - filter(("O"."TYPE#"<>10 AND "O"."NAME"<>'_NEXT_OBJECT' AND "O"."NAME"<>'_default_auditing_options_' AND "O"."LINKNAME" IS NULL AND BITAND("O"."FLAGS",128)=0)) 11 - access("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_id'))) filter(("U2"."TYPE#"=2 AND "U2"."SPARE2"=TO_NUMBER(SYS_CONTEXT('userenv','current_edition_id')))) 12 - access("O2"."DATAOBJ#"=:B1 AND "O2"."TYPE#"=88 AND "O2"."OWNER#"="U2"."USER#") 16 - access("L"."OWNER#"="U"."USER#") 45 rows selected. SQL> |
如果我们没有加hint:随便执行一条SQL,然后查详细的执行计划
SQL> select * from table(dbms_xplan.display_cursor()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID dyk4dprp70d74, child number 0 ------------------------------------- SELECT DECODE('A','A','1','2') FROM DUAL Plan hash value: 1388734953 ----------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ----------------------------------------------------------------- | 0 | SELECT STATEMENT | | | 2 (100)| | | 1 | FAST DUAL | | 1 | 2 (0)| 00:00:01 | ----------------------------------------------------------------- 13 rows selected. SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 738a0r0utp4wv, child number 0 ------------------------------------- select * from table(dbms_xplan.display_cursor()) Plan hash value: 3713220770 --------------------------------------------------------------------- | Id | Operation | Name | E-Rows | --------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 | COLLECTION ITERATOR PICKLER FETCH| DISPLAY_CURSOR | 8168 | --------------------------------------------------------------------- Note ----- - Warning: basic plan statistics not available. These are only collected when: * hint 'gather_plan_statistics' is used for the statement or * parameter 'statistics_level' is set to 'ALL', at session or system level 19 rows selected. SQL> |
就会报一个错:
* hint 'gather_plan_statistics' is used for the statement or
加个hint
* parameter 'statistics_level' is set to 'ALL', at session or system level
或者把statistics_level设为ALL
因为加了ALLSTATS,所以他会去访问plan statistics执行计划的统计信息,然后给出以上两种方式
statistics_level设为ALL
SQL> alter session set statistics_level=ALL; Session altered. SQL> select count(*) from dba_tables; COUNT(*) ---------- 2826 SQL> select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 56bs32ukywdsq, child number 0 ------------------------------------- select count(*) from dba_tables Plan hash value: 1678981737 ------------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | O/1/M | ------------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.15 | 3199 | | | | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.15 | 3199 | | | | |* 2 | HASH JOIN RIGHT OUTER | | 1 | 6095 | 2826 |00:00:00.15 | 3199 | 1645K| 1645K| 1/0/0| | 3 | TABLE ACCESS FULL | SEG$ | 1 | 5867 | 5867 |00:00:00.01 | 175 | | | | |* 4 | HASH JOIN RIGHT OUTER | | 1 | 2828 | 2826 |00:00:00.14 | 3024 | 2440K| 2440K| 1/0/0| | 5 | INDEX FULL SCAN | I_USER2 | 1 | 89 | 90 |00:00:00.01 | 1 | | | | |* 6 | HASH JOIN OUTER | | 1 | 2828 | 2826 |00:00:00.14 | 3023 | 1519K| 1519K| 1/0/0| |* 7 | HASH JOIN | | 1 | 2828 | 2826 |00:00:00.11 | 2765 | 2440K| 2440K| 1/0/0| | 8 | INDEX FULL SCAN | I_USER2 | 1 | 89 | 90 |00:00:00.01 | 1 | | | | |* 9 | HASH JOIN | | 1 | 2828 | 2826 |00:00:00.11 | 2764 | 1344K| 1344K| 1/0/0| |* 10 | HASH JOIN OUTER | | 1 | 2828 | 2828 |00:00:00.06 | 1692 | 1301K| 1301K| 1/0/0| |* 11 | HASH JOIN | | 1 | 2828 | 2828 |00:00:00.02 | 1434 | 2616K| 2616K| 1/0/0| | 12 | MERGE JOIN CARTESIAN| | 1 | 7 | 7 |00:00:00.01 | 8 | | | | |* 13 | HASH JOIN | | 1 | 1 | 1 |00:00:00.01 | 0 | 2293K| 2293K| 1/0/0| |* 14 | FIXED TABLE FULL | X$KSPPI | 1 | 1 | 1 |00:00:00.01 | 0 | | | | | 15 | FIXED TABLE FULL | X$KSPPCV | 1 | 100 | 2914 |00:00:00.01 | 0 | | | | | 16 | BUFFER SORT | | 1 | 7 | 7 |00:00:00.01 | 8 | 73728 | 73728 | | | 17 | TABLE ACCESS FULL | TS$ | 1 | 7 | 7 |00:00:00.01 | 8 | | | | |* 18 | TABLE ACCESS FULL | TAB$ | 1 | 2828 | 2828 |00:00:00.01 | 1426 | | | | | 19 | INDEX FAST FULL SCAN | I_OBJ1 | 1 | 86392 | 86440 |00:00:00.01 | 258 | | | | |* 20 | TABLE ACCESS FULL | OBJ$ | 1 | 86392 | 86437 |00:00:00.02 | 1072 | | | | | 21 | INDEX FAST FULL SCAN | I_OBJ1 | 1 | 86392 | 86440 |00:00:00.01 | 258 | | | | ------------------------------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("T"."FILE#"="S"."FILE#" AND "T"."BLOCK#"="S"."BLOCK#" AND "T"."TS#"="S"."TS#") 4 - access("CX"."OWNER#"="CU"."USER#") 6 - access("T"."DATAOBJ#"="CX"."OBJ#") 7 - access("O"."OWNER#"="U"."USER#") 9 - access("O"."OBJ#"="T"."OBJ#") 10 - access("T"."BOBJ#"="CO"."OBJ#") 11 - access("T"."TS#"="TS"."TS#") 13 - access("KSPPI"."INDX"="KSPPCV"."INDX") 14 - filter("KSPPI"."KSPPINM"='_dml_monitoring_enabled') 18 - filter(BITAND("T"."PROPERTY",1)=0) 20 - filter(BITAND("O"."FLAGS",128)=0) 48 rows selected. SQL> |