读懂执行计划
查看执行计划的方法
- Explain Plan For SQL
• 不实际执行SQL语句,生成的计划未必是真实执行的计划
• 必须要有plan_table
是一种手段但不是最好的 - SQLPLUS AUTOTRACE
• 除set autotrace traceonly explain外均实际执行SQL,但仍未必
是真实计划
• 必须要有plan_table - SQL TRACE
• 需要启用10046戒者SQL_TRACE
• 一般用tkprof看的更清楚些,当然10046里本身也有执行计划信息 - V$SQL和V$SQL_PLAN
• 可以查询到多个子游标的计划信息了,但是看起来比较费劲 - Enterprise Manager
• 可以图形化显示执行计划,但并非所有环境有EM可用 - 其他第三方工具
• 注意 PL/SQL developer之类工具F5看到的执行计划未必是真实的
D:\instantclient_12_2>sqlplus scott/tiger@clonepdb_plug
SQL*Plus: Release 12.2.0.1.0 Production on Fri Jan 12 13:54:31 2018
Copyright (c) 1982, 2016, Oracle. All rights reserved.
Last Successful login time: Fri Jan 12 2018 11:18:59 +08:00
Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
SCOTT@clonepdb_plug>set linesize 180
SCOTT@clonepdb_plug>set pagesize 0
SCOTT@clonepdb_plug>alter session set STATISTICS_LEVEL = ALL;
Session altered.
SCOTT@clonepdb_plug>select * from emp where ename='SMITH';
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20
SCOTT@clonepdb_plug>select * from table(dbms_xplan.display_cursor(null,null,'allstats'));
SQL_ID cgf95c3k5mszx, child number 0
select * from emp where ename='SMITH'
Plan hash value: 3956160932
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 8 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 1 | 1 |00:00:00.01 | 8 |
Predicate Information (identified by operation id):
1 - filter("ENAME"='SMITH')
18 rows selected.
SCOTT@clonepdb_plug>
需要授权
grant select on v$session to scott;
grant select on v$sql to scott;
grant select on v_$sqlplan to scott;
grant select on v$sql_plan_statistics_all to scott;
- 基本字段(总是可用的)
Id 执行计划中每一个操作(行)的标识符。如果数字前面带有星号,意味着将在随后提供这行包含的谓词信息
Operation 对应执行的操作。也叫行源操作
Name 操作的对象名称
2.查询优化器评估信息
Rows(E-Rows) 预估操作返回的记录条数
Bytes(E-Bytes) 预估操作返回的记录字节数
TempSpc 预估操作使用临时表空间的大小
Cost(%CPU) 预估操作所需的开销。在括号中列出了CPU开销的百分比。注意这些值是通过执行计划计算出来的。换句话说,父操作的开销包含子操作的开销
Time 预估执行操作所需要的时间(HH:MM:SS)
3.分区(仅当访问分区表时下列字段可见)
Pstart 访问的第一个分区。如果解析时不知道是哪个分区就设为KEY,KEY(I),KEY(MC),KEY(OR),KEY(SQ)
Pstop 访问的最后一个分区。如果解析时不知道是哪个分区就设为KEY,KEY(I),KEY(MC),KEY(OR),KEY(SQ)
4.并行和分布式处理(仅当使用并行或分布式操作时下列字段可见)
Inst 在分布式操作中,指操作使用的数据库链接的名字
TQ 在并行操作中,用于从属线程间通信的表队列
IN-OUT 并行或分布式操作间的关系
PQ Distrib 在并行操作中,生产者为发送数据给消费者进行的分配
5.运行时统计(当设定参数statistics_level为all或使用gather_plan_statistics提示时,下列字段可见)
Starts 指定操作执行的次数
A-Rows 操作返回的真实记录数
A-Time 操作执行的真实时间(HH:MM:SS.FF)
6.I/O 统计(当设定参数statistics_level为all或使用gather_plan_statistics提示时,下列字段可见)
Buffers 执行期间进行的逻辑读操作数量
Reads 执行期间进行的物理读操作数量
Writes 执行期间进行的物理写操作数量
7.内存使用统计
OMem 最优执行所需内存的预估值
1Mem 一次通过(one-pass)执行所需内存的预估值
0/1/M 最优/一次通过/多次通过(multipass)模式操作执行的次数
Used-Mem 最后一次执行时操作使用的内存量
Used-Tmp 最后一次执行时操作使用的临时空间大小。这个字段必须扩大1024倍才能和其他衡量内存的字段一致(比如,32k意味着32MB)
Max-Tmp 操作使用的最大临时空间大小。这个字段必须扩大1024倍才能和其他衡量内存的字段一致(比如,32k意味着32MB)
例
SCOTT@clonepdb_plug>explain plan for
2 select * from emp e,dept d
3 where e.deptno=d.deptno
4 and e.ename='SMITH';
Explained.
SCOTT@clonepdb_plug>select from table(dbms_xplan.display(null,null,'advanced'));
Plan hash value: 3625962092 -----是指执行计划转成的hash值,和执行效率无关,执行计划的唯一标示
/执行计划部分*/
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 1 | 59 | 4 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 59 | 4 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 59 | 4 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | EMP | 1 | 39 | 3 (0)| 00:00:01 |
| 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 1 (0)| 00:00:01 |
Query Block Name / Object Alias (identified by operation id): --这部分显示的为查询块名和对象别名
3 - SEL$1 / E@SEL$1 -E@SEL$1,对应到执行计划中的操作ID为3上,即在表E上的查询,E为别名,下面类同 SEL$为select 的缩写,位于块1,相应的还有DEL$,INS$,UPD$等
4 - SEL$1 / D@SEL$1
5 - SEL$1 / D@SEL$1
Outline Data --提纲部分,这部分将执行计划中的图形化方式以文本形式来呈现,即转换为提示符方式
/+
BEGIN_OUTLINE_DATA
NLJ_BATCHING(@"SEL$1" "D"@"SEL$1") --指示优化器以嵌套循环关联预提取的方式访问表
USE_NL(@"SEL$1" "D"@"SEL$1") --使用USE_NL提示,即嵌套循环
LEADING(@"SEL$1" "E"@"SEL$1" "D"@"SEL$1") --指明前导表
INDEX(@"SEL$1" "D"@"SEL$1" ("DEPT"."DEPTNO"))-指明对于D上的访问方式为使用索引
FULL(@"SEL$1" "E"@"SEL$1") --指明对于E上的访问方式为全表扫描 OUTLINE_LEAF(@"SEL$1")
br/>OUTLINE_LEAF(@"SEL$1")
DB_VERSION('12.2.0.1')
OPTIMIZER_FEATURES_ENABLE('12.2.0.1')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
/
Predicate Information (identified by operation id):--谓词信息部分,在执行计划中ID带有星号的每一行均对应到下面中的一行
3 - filter("E"."ENAME"='SMITH')
4 - access("E"."DEPTNO"="D"."DEPTNO")
Column Projection Information (identified by operation id):--执行时每一步骤所返回的列,下面的不同步骤返回了不同的列
1 - (#keys=0) "E"."EMPNO"[NUMBER,22], "E"."ENAME"[VARCHAR2,10],
"E"."JOB"[VARCHAR2,9], "E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7],
"E"."SAL"[NUMBER,22], "E"."COMM"[NUMBER,22], "E"."DEPTNO"[NUMBER,22],
"D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,14], "D"."LOC"[VARCHAR2,13]
2 - (#keys=0) "E"."EMPNO"[NUMBER,22], "E"."ENAME"[VARCHAR2,10],
"E"."JOB"[VARCHAR2,9], "E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7],
"E"."SAL"[NUMBER,22], "E"."COMM"[NUMBER,22], "E"."DEPTNO"[NUMBER,22],
"D".ROWID[ROWID,10], "D"."DEPTNO"[NUMBER,22]
3 - "E"."EMPNO"[NUMBER,22], "E"."ENAME"[VARCHAR2,10], "E"."JOB"[VARCHAR2,9],
"E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7], "E"."SAL"[NUMBER,22],
"E"."COMM"[NUMBER,22], "E"."DEPTNO"[NUMBER,22]
4 - "D".ROWID[ROWID,10], "D"."DEPTNO"[NUMBER,22]
5 - "D"."DNAME"[VARCHAR2,14], "D"."LOC"[VARCHAR2,13]
Note--注释与描述部分,下面的描述中给出了本次SQL语句使用了动态采样功能
- this is an adaptive plan
64 rows selected.
例
SCOTT@clonepdb_plug>select /+ gather_plan_statistics / * from emp e,dept d
2 where e.deptno=d.deptno
3 and e.ename='SMITH';
--注意此处增加了提示gather_plan_statistics并且该语句被执行 等同于alter session set STATISTICS_LEVEL = ALL;
7369 SMITH CLERK 7902 1980-12-17 00:00:00 800 20 20 RESEARCH
DALLAS
SCOTT@clonepdb_plug>select * from table(dbms_xplan.display_cursor(null,null,'iostats last'));--使用display_cursor获取实际的执行计划
SQL_ID 0wb0wwb3621n2, child number 0 --这部分给出了SQL语句的SQL_ID,子游标号以及原始的SQL语句
select /+ gather_plan_statistics / * from emp e,dept d
where e.deptno=d.deptno and e.ename='SMITH'
Plan hash value: 3625962092
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 9 |
| 1 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 9 |
| 2 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 8 |
| 3 | TABLE ACCESS FULL | EMP | 1 | 1 | 1 |00:00:00.01 | 7 |
| 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 1 | 1 |00:00:00.01 | 1 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 1 | 1 |00:00:00.01 | 1 |
Predicate Information (identified by operation id):
3 - filter("E"."ENAME"='SMITH')
4 - access("E"."DEPTNO"="D"."DEPTNO")
Note
this is an adaptive plan
28 rows selected.SCOTT@clonepdb_plug>select * from table(dbms_xplan.display_cursor('6h2msdzb5hj7s',null,'ADVANCED peeked_binds ALLSTATS'));
SQL_ID 6h2msdzb5hj7s, child number 0select /+ gather_plan_statistics / * from emp e,dept d
where e.deptno=d.deptno and rownum<20 and ename like
'%I%'
Plan hash value: 2662388210
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | OMem | 1Mem | O/1/M |
| 0 | SELECT STATEMENT | | 1 | | | 4 (100)| | 4 |00:00:00.02 | 15 | | | |
| 1 | COUNT STOPKEY | | 1 | | | | | 4 |00:00:00.02 | 15 | | | |
| 2 | HASH JOIN | | 1 | 1 | 59 | 4 (0)| 00:00:01 | 4 |00:00:00.02 | 15 | 1055K| 1055K| 1/0/0|
|* 3 | TABLE ACCESS FULL| EMP | 1 | 1 | 39 | 3 (0)| 00:00:01 | 4 |00:00:00.01 | 7 | | | |
| 4 | TABLE ACCESS FULL| DEPT | 1 | 1 | 20 | 1 (0)| 00:00:01 | 3 |00:00:00.01 | 8 | | | |
Query Block Name / Object Alias (identified by operation id):
1 - SEL$1
3 - SEL$1 / E@SEL$1
4 - SEL$1 / D@SEL$1
Outline Data
/+
BEGIN_OUTLINE_DATA
FULL(@"SEL$1" "D"@"SEL$1")
USE_HASH(@"SEL$1" "D"@"SEL$1")IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('12.2.0.1')
DB_VERSION('12.2.0.1')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
br/>IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('12.2.0.1')
DB_VERSION('12.2.0.1')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
LEADING(@"SEL$1" "E"@"SEL$1" "D"@"SEL$1")
END_OUTLINE_DATA
/
Predicate Information (identified by operation id):
1 - filter(ROWNUM<20)
2 - access("E"."DEPTNO"="D"."DEPTNO")
3 - filter(("ENAME" LIKE '%I%' AND "ENAME" IS NOT NULL))
Column Projection Information (identified by operation id):
1 - "E"."DEPTNO"[NUMBER,22], "D"."DEPTNO"[NUMBER,22], "E"."EMPNO"[NUMBER,22], "ENAME"[VARCHAR2,10], "E"."JOB"[VARCHAR2,9],
"E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7], "E"."SAL"[NUMBER,22], "E"."COMM"[NUMBER,22], "D"."LOC"[VARCHAR2,13],
"D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,14], "D"."LOC"[VARCHAR2,13], "D"."DNAME"[VARCHAR2,14]
2 - (#keys=1) "E"."DEPTNO"[NUMBER,22], "D"."DEPTNO"[NUMBER,22], "E"."EMPNO"[NUMBER,22], "ENAME"[VARCHAR2,10], "E"."JOB"[VARCHAR2,9],
"E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7], "E"."SAL"[NUMBER,22], "E"."COMM"[NUMBER,22], "D"."LOC"[VARCHAR2,13],
"D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,14], "D"."LOC"[VARCHAR2,13], "D"."DNAME"[VARCHAR2,14]
3 - "E"."EMPNO"[NUMBER,22], "ENAME"[VARCHAR2,10], "E"."JOB"[VARCHAR2,9], "E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7],
"E"."SAL"[NUMBER,22], "E"."COMM"[NUMBER,22], "E"."DEPTNO"[NUMBER,22]
4 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,14], "D"."LOC"[VARCHAR2,13]
Note
- this is an adaptive plan
66 rows selected.
SCOTT@clonepdb_plug>