为什么要有执行计划
因为Oracle的SQL语言是一种“傻瓜”式的语言,需要交给优化器去判断怎么访问更快。
Oracle的执行计划准吗(搜集统计信息)
比如小表驱动大表效率比大表驱动小表更快。那Oracle是怎么知道哪个是小表哪个是大表呢,Oracle的执行计划准吗?
这个就涉及到Oracle收集统计信息。比如Oracle 11g1默认启动了统计信息收集的任务(也可以关闭自动统计新收集任务,选择手工收集的方式,但是一般不建议这样操作),就是周一到周五晚上十点统计相应信息,周六周日早上六点搜集统计信息,比如搜集表的数据大小、索引、列的相关信息(比如列上面的数据有没有倾斜,意思就是比如表中的某一列的数据大部分都是某个值A,只有很少的数据是另一种值B,我们就说数据是倾斜的,那么在查询的时候,如果查询的是A就会全表扫描,是B就会走索引)等。
但是还有一种情况,Oracle 11g就是周一到周五晚上十点统计相应信息,那假如在早上八点新建了一张表,那么这张表的数据不久无法统计了吗,Oracle还有一种动态采样机制,即如果没有搜集到统计信息,那么Oracle会采用动态采样的方式去搜集统计信息。这时候搜集的统计信息不会像搜集统计信息那样放到数据字典中,而是会放到内存中。
Oracle也会在建索引的过程中动态的搜集统计信息。
可以执行这段SQL查看Oracle搜集统计信息的日志:
select window_name,
window_next_time,
autotask_status,
optimizer_stats
from DBA_AUTOTASK_WINDOW_CLIENTS;
获取执行计划的方法
6种方法:
1. explain plan for获取(即PL/SQL中的F5);
2. set autotrace on (跟踪性能统计);
3. statistics_level=all(获取表访问次数);
4. 通过dbms_xplan.display_cursor输入sql_id参数直接获取
5. 10046 trace跟踪
6. awrsqrpt.sql
各自的适用场景:
1.如果某SQL执行非常长时间才会出结果,甚至慢到返回不了结果,这时候看执行计划就只能用方法1,或者方法4调用现成的;
2.跟踪某条SQL最简单的方法是方法1,其次就是方法2;
3.如果想观察到某条SQL有多条执行计划的情况,只能用方法4和方法6;
4.如果SQL中含有多函数,函数中套有SQL等多层递归调用,想准确分析,只能使用方法5;
5.要想确保看到真实的执行计划,不能用方法1和方法2;
6.要想获取表被访问的次数,只能使用方法3;
读懂执行计划
环境准备:
DROP TABLE t1 CASCADE CONSTRAINTS PURGE;
DROP TABLE t2 CASCADE CONSTRAINTS PURGE;
CREATE TABLE t1 (
id NUMBER NOT NULL,
n NUMBER,
contents VARCHAR2(4000)
)
;
CREATE TABLE t2 (
id NUMBER NOT NULL,
t1_id NUMBER NOT NULL,
n NUMBER,
contents VARCHAR2(4000)
)
;
execute dbms_random.seed(0);
INSERT INTO t1
SELECT rownum, rownum, dbms_random.string('a', 50)
FROM dual
CONNECT BY level <= 1000
ORDER BY dbms_random.random;
INSERT INTO t2 SELECT rownum, rownum, rownum, dbms_random.string('b', 50) FROM dual CONNECT BY level <= 100000
ORDER BY dbms_random.random;
COMMIT;
CREATE INDEX t1_n ON t1 (n);
CREATE INDEX t2_t1_id ON t2(t1_id);
接下来使用多种方式查看这条SQL的执行计划:
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
第一种方法(explain plan for 的方式。类似PLSQL DEVELOPE里的F5)
这种方法的详细介绍可参看:https://blog.csdn.net/Dongguabai/article/details/84309062
步骤1:explain plan for "你的SQL"
步骤2:select * from table(dbms_xplan.display());
执行SQL(有时候会需要先exit一下):
set linesize 1000
set pagesize 2000
explain plan for
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
select * from table(dbms_xplan.display());
也可以在PL/SQL里面F5查看:
基本上只要一提到执行计划,很多人都会想到这个方法,但是要注意的是使用这种方式查看到的执行计划是预估的值,也就是说数据是假的。
优点: 1.无需真正执行,快捷方便
缺陷: 1.没有输出运行时的相关统计信息(产生多少逻辑读,多少次递归调用,多少次物理读的情况);
2.无法判断是处理了多少行;
3.无法判断表被访问了多少次。
确实啊,这毕竟都没有真正执行又如何得知真实运行产生的统计信息。
第二种方式(set autotrace on 方式)
步骤1:set autotrace on
步骤2:在此处执行你的SQL即可,后续自然会有结果输出
有如下命令
set autotrace on (得到执行计划,输出运行结果)
set autotrace traceonly (得到执行计划,不输出运行结果)
set autotrace traceonly explain (得到执行计划,不输出运行结果和统计信息部分,仅展现执行计划部分)
set autotrace traceonl statistics(不输出运行结果和执行计划部分,仅展现统计信息部分)
Autotrace执行计划的各列的涵义
序号 列名 解释
1 ID_PLUS_EXP 每一步骤的行号
2 PARENT_ID_PLUS_EXP 每一步的Parent的级别号
3 PLAN_PLUS_EXP 实际的每步
4 OBJECT_NODE_PLUS_EXP Dblink或并行查询时才会用到
四、AUTOTRACE Statistics常用列解释
序号 统计列 解释
1 db block gets 从buffer cache中读取的block的数量
2 consistent gets 从buffer cache中读取的undo数据的block的数量
3 physical reads 从磁盘读取的block的数量
4 redo size DML生成的redo的大小
5 sorts (memory) 在内存执行的排序量
7 sorts (disk) 在磁盘上执行的排序量
执行SQL:
set autotrace on
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
可以看到这种方式相比第一种方法能够获取更多的信息。
优点:1.可以输出运行时的相关统计信息(产生多少逻辑读,多少次递归调用,多少次物理读的情况);
2.虽然必须要等语句执行完毕后才可以输出执行计划,但是可以有traceonly开关来控制返回结果不打屏输出。
缺陷:1.必须要等到语句真正执行完毕后,才可以出结果;
2.无法看到表被访问了多少次。
第三种方式(statistics level=all的方式)
步骤1:alter session set statistics_level=all ;
步骤2:在此处执行你的SQL
步骤3:select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
另注:
1. 如果你用 /*+ gather_plan_statistics */的方法,可以省略步骤1,直接步骤2,3。
2. 关键字解读(其中OMem、1Mem和User-Mem在后续的课程中会陆续见到):
- Starts为该sql执行的次数。
- E-Rows为执行计划预计的行数。
- A-Rows为实际返回的行数。A-Rows跟E-Rows做比较,就可以确定哪一步执行计划出了问题。
- A-Time为每一步实际执行的时间(HH:MM:SS.FF),根据这一行可以知道该sql耗时在了哪个地方。
- Buffers为每一步实际执行的逻辑读或一致性读。
- Reads为物理读。
- OMem:当前操作完成所有内存工作区(Work Aera)操作所总共使用私有内存(PGA)中工作区的大小,这个数据是由优化器统计数据以及前一次执行的性能数据估算得出的
- 1Mem:当工作区大小无法满足操作所需的大小时,需要将部分数据写入临时磁盘空间中(如果仅需要写入一次就可以完成 操作,就称一次通过,One-Pass;否则为多次通过,Multi_Pass).该列数据为语句最后一次执行中,单次写磁盘所需要的内存大小,这个由优化器统计数据以及前一次执行的性能数据估算得出的。
- User-Mem:语句最后一次执行中,当前操作所使用的内存工作区大小,括号里面为(发生磁盘交换的次数,1次即为One- Pass,大于1次则为Multi_Pass,如果没有使用磁盘,则显示OPTIMAL)
- OMem、1Mem为执行所需的内存评估值,0Mem为最优执行模式所需内存的评估值,1Mem为one-pass模式所需内存的评估值。
- 0/1/M 为最优/one-pass/multipass执行的次数。Used-Mem耗的内存
执行这样一段SQL:
set autotrace off
alter session set statistics_level=all ;
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
优点:1.可以清晰的从STARTS得出表被访问多少(因为表的访问开销是很大的,这是很重要的一点)。
2.可以清晰的从E-ROWS和A-ROWS中得到预测的行数和真实的行数,从而可以准确判断Oracle评估是否准确(很重要的一点)。
3.虽然没有专门的输出运行时的相关统计信息,但是执行计划中的BUFFERS就是真实的逻辑读的多少
缺陷:1.必须要等到语句真正执行完毕后,才可以出结果。
2.无法控制记录输屏打出,不像autotrace有 traceonly 可以控制不将结果打屏输出。
3.看不出递归调用的次数,看不出物理读的多少(不过逻辑读才是重点)
第四种方式(知道sql_id后,直接带入的方式,简单)
步骤1: select * from table(dbms_xplan.display_cursor('&sq_id')); (该方法是从共享池里得到)
可以通过:
select * from v$sql
查看sql_id:
执行结果:
注:
1. 还有一个方法,select * from table(dbms_xplan.display_awr('&sq_id'));(这是awr性能视图里获取到的)
2. 如果有多执行计划,可以用类似方法查出(0、1、2...)
select * from table(dbms_xplan.display_cursor('cyzznbykb509s',0));
select * from table(dbms_xplan.display_cursor('cyzznbykb509s',1));
优点:1.知道sql_id立即可得到执行计划,和explain plan for 一样无需执行;
2.可以得到真实的执行计划。(停,等等,啥真实的,刚才这几个套路中,还有假的执行计划的吗?)
缺陷: 1.没有输出运行时的相关统计信息(产生多少逻辑读,多少次递归调用,多少次物理读的情况);
2.无法判断是处理了多少行;
3.无法判断表被访问了多少次。
第五种方式(10046TRACE)
步骤1:alter session set events '10046 trace name context forever,level 12'; (开启跟踪)
步骤2:执行你的语句
步骤3:alter session set events '10046 trace name context off'; (关闭跟踪)
步骤4:找到跟踪后产生的文件
步骤5:tkprof trc文件 目标文件(没有目标文件会弹出打开窗口) sys=no sort=prsela,exeela,fchela (格式化命令)
执行:
set autotace off
alter session set statistics_level=typical;
alter session set events '10046 trace name context forever,level 12';
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19);
alter session set events '10046 trace name context off';
步骤四:
select d.value
|| '/'
|| LOWER (RTRIM(i.INSTANCE, CHR(0)))
|| '_ora_'
|| p.spid
|| '.trc' trace_file_name
from (select p.spid
from v$mystat m,v$session s, v$process p
where m.statistic#=1 and s.sid=m.sid and p.addr=s.paddr) p,
(select t.INSTANCE
FROM v$thread t,v$parameter v
WHERE v.name='thread'
AND(v.VALUE=0 OR t.thread#=to_number(v.value))) i,
(select value
from v$parameter
where name='user_dump_dest') d;
退出,进入cmd:
tkprof C:\oraclexe\app\oracle\diag\rdbms\xe\xe\trace/xe_ora_16272.trc d:\10046.txt sys=no sort=prsela,exeela,fchela
进入cmd执行:
查看文件:
Trace file C:\ORACLEXE\APP\ORACLE\diag\rdbms\xe\xe\trace\xe_ora_16272.trc
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
Windows NT Version V6.2
CPU : 4 - type 8664, 4 Physical Cores
Process Affinity : 0x0x0000000000000000
Memory (Avail/Total): Ph:3114M/8067M, Ph+PgF:2504M/14738M
Instance name: xe
Redo thread mounted by this instance: 1
Oracle process number: 29
Windows thread id: 16272, image: ORACLE.EXE (SHAD)
*** 2018-11-20 20:46:53.020
*** SESSION ID:(33.507) 2018-11-20 20:46:53.021
*** CLIENT ID:() 2018-11-20 20:46:53.021
*** SERVICE NAME:(SYS$USERS) 2018-11-20 20:46:53.021
*** MODULE NAME:(SQL*Plus) 2018-11-20 20:46:53.021
*** ACTION NAME:() 2018-11-20 20:46:53.021
WAIT #364949696: nam='SQL*Net message to client' ela= 9 driver id=1111838976 #bytes=1 p3=0 obj#=6310 tim=386198577398
*** 2018-11-20 20:47:05.624
WAIT #364949696: nam='SQL*Net message from client' ela= 12602044 driver id=1111838976 #bytes=1 p3=0 obj#=6310 tim=386211195110
CLOSE #364949696:c=0,e=38,dep=0,type=0,tim=386211195581
=====================
PARSING IN CURSOR #364297880 len=582 dep=1 uid=62 oct=3 lid=62 tim=386211199184 hv=3194033346 ad='7ffb17d29ce0' sqlid='gwht6tqz62562'
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1"), COUNT(DISTINCT C3), NVL(SUM(CASE WHEN C3 IS NULL THEN :"SYS_B_2" ELSE :"SYS_B_3" END),:"SYS_B_4") FROM (SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T1") FULL("T1") NO_PARALLEL_INDEX("T1") */ :"SYS_B_5" AS C1, CASE WHEN "T1"."N"=:"SYS_B_6" OR "T1"."N"=:"SYS_B_7" THEN :"SYS_B_8" ELSE :"SYS_B_9" END AS C2, "T1"."ID" AS C3 FROM "BDATAGER"."T1" "T1") SAMPLESUB
END OF STMT
PARSE #364297880:c=0,e=456,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,plh=0,tim=386211199183
BINDS #364297880:
Bind#0
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=17e8f8d0 bln=22 avl=01 flg=09
value=0
Bind#1
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=2194a158 bln=22 avl=01 flg=09
value=0
Bind#2
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c0bcc58 bln=22 avl=02 flg=09
value=1
Bind#3
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=20451170 bln=22 avl=01 flg=09
value=0
Bind#4
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c177428 bln=22 avl=01 flg=09
value=0
Bind#5
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1e1af338 bln=22 avl=02 flg=09
value=1
Bind#6
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c0b0378 bln=22 avl=02 flg=09
value=18
Bind#7
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c0c1768 bln=22 avl=02 flg=09
value=19
Bind#8
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c1518a0 bln=22 avl=02 flg=09
value=1
Bind#9
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c14ebc8 bln=22 avl=01 flg=09
value=0
EXEC #364297880:c=15625,e=5380,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,plh=405047221,tim=386211207437
FETCH #364297880:c=0,e=1329,p=0,cr=16,cu=0,mis=0,r=1,dep=1,og=1,plh=405047221,tim=386211208864
STAT #364297880 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT AGGREGATE (cr=16 pr=0 pw=0 time=1364 us)'
STAT #364297880 id=2 cnt=1000 pid=1 pos=1 obj=0 op='VIEW VW_DAG_0 (cr=16 pr=0 pw=0 time=1014 us cost=3 size=4264 card=82)'
STAT #364297880 id=3 cnt=1000 pid=2 pos=1 obj=0 op='HASH GROUP BY (cr=16 pr=0 pw=0 time=1011 us cost=3 size=2132 card=82)'
STAT #364297880 id=4 cnt=1000 pid=3 pos=1 obj=39001 op='TABLE ACCESS FULL T1 (cr=16 pr=0 pw=0 time=158 us cost=2 size=2132 card=82)'
CLOSE #364297880:c=0,e=17,dep=1,type=0,tim=386211210403
=====================
PARSING IN CURSOR #364297880 len=544 dep=1 uid=62 oct=3 lid=62 tim=386211212165 hv=2462745574 ad='7ffb17d197d0' sqlid='bfuv67y9cp0z6'
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false') NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"), NVL(SUM(C2),:"SYS_B_1"), COUNT(DISTINCT C3), NVL(SUM(CASE WHEN C3 IS NULL THEN :"SYS_B_2" ELSE :"SYS_B_3" END),:"SYS_B_4") FROM (SELECT /*+ NO_PARALLEL("T2") FULL("T2") NO_PARALLEL_INDEX("T2") */ :"SYS_B_5" AS C1, :"SYS_B_6" AS C2, "T2"."T1_ID" AS C3 FROM "BDATAGER"."T2" SAMPLE BLOCK (:"SYS_B_7" , :"SYS_B_8") SEED (:"SYS_B_9") "T2") SAMPLESUB
END OF STMT
PARSE #364297880:c=0,e=1054,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,plh=0,tim=386211212164
BINDS #364297880:
Bind#0
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c183328 bln=22 avl=01 flg=09
value=0
Bind#1
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c25d908 bln=22 avl=01 flg=09
value=0
Bind#2
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c17f8a8 bln=22 avl=02 flg=09
value=1
Bind#3
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1e18db48 bln=22 avl=01 flg=09
value=0
Bind#4
oacdty=02 mxl=22(01) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c25d700 bln=22 avl=01 flg=09
value=0
Bind#5
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0500 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c1c1be8 bln=22 avl=02 flg=09
value=1
Bind#6
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0500 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c1710f8 bln=22 avl=02 flg=09
value=1
Bind#7
oacdty=02 mxl=22(03) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c33f9f8 bln=22 avl=03 flg=09
value=6.3
Bind#8
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c28a8f0 bln=22 avl=02 flg=09
value=1
Bind#9
oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
oacflg=10 fl2=0100 frm=00 csi=00 siz=24 off=0
kxsbbbfp=1c1fea68 bln=22 avl=02 flg=09
value=1
EXEC #364297880:c=0,e=4410,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,plh=1741831035,tim=386211217774
FETCH #364297880:c=15625,e=3785,p=0,cr=78,cu=0,mis=0,r=1,dep=1,og=1,plh=1741831035,tim=386211221639
STAT #364297880 id=1 cnt=1 pid=0 pos=1 obj=0 op='SORT AGGREGATE (cr=78 pr=0 pw=0 time=3814 us)'
STAT #364297880 id=2 cnt=7347 pid=1 pos=1 obj=0 op='VIEW VW_DAG_0 (cr=78 pr=0 pw=0 time=3917 us cost=3 size=195 card=5)'
STAT #364297880 id=3 cnt=7347 pid=2 pos=1 obj=0 op='HASH GROUP BY (cr=78 pr=0 pw=0 time=3282 us cost=3 size=125 card=5)'
STAT #364297880 id=4 cnt=7347 pid=3 pos=1 obj=39002 op='TABLE ACCESS SAMPLE T2 (cr=78 pr=0 pw=0 time=154 us cost=2 size=125 card=5)'
CLOSE #364297880:c=0,e=6,dep=1,type=0,tim=386211222022
=====================
PARSING IN CURSOR #364949696 len=63 dep=0 uid=62 oct=3 lid=62 tim=386211223339 hv=116898580 ad='7ffb17d5ea68' sqlid='1a914ws3ggfsn'
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n in(18,19)
END OF STMT
PARSE #364949696:c=31250,e=27620,p=0,cr=98,cu=0,mis=1,r=0,dep=0,og=1,plh=3532430033,tim=386211223338
EXEC #364949696:c=0,e=60,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3532430033,tim=386211224412
WAIT #364949696: nam='SQL*Net message to client' ela= 4 driver id=1111838976 #bytes=1 p3=0 obj#=6310 tim=386211224541
FETCH #364949696:c=0,e=38,p=0,cr=6,cu=0,mis=0,r=1,dep=0,og=1,plh=3532430033,tim=386211224675
WAIT #364949696: nam='SQL*Net message from client' ela= 335 driver id=1111838976 #bytes=1 p3=0 obj#=6310 tim=386211225520
WAIT #364949696: nam='SQL*Net message to client' ela= 2 driver id=1111838976 #bytes=1 p3=0 obj#=6310 tim=386211225652
FETCH #364949696:c=0,e=116,p=0,cr=8,cu=0,mis=0,r=1,dep=0,og=1,plh=3532430033,tim=386211225728
STAT #364949696 id=1 cnt=2 pid=0 pos=1 obj=0 op='NESTED LOOPS (cr=14 pr=0 pw=0 time=72 us)'
STAT #364949696 id=2 cnt=2 pid=1 pos=1 obj=0 op='NESTED LOOPS (cr=12 pr=0 pw=0 time=99 us cost=8 size=8138 card=2)'
STAT #364949696 id=3 cnt=2 pid=2 pos=1 obj=0 op='INLIST ITERATOR (cr=7 pr=0 pw=0 time=73 us)'
STAT #364949696 id=4 cnt=2 pid=3 pos=1 obj=39001 op='TABLE ACCESS BY INDEX ROWID T1 (cr=7 pr=0 pw=0 time=70 us cost=4 size=4056 card=2)'
STAT #364949696 id=5 cnt=2 pid=4 pos=1 obj=39003 op='INDEX RANGE SCAN T1_N (cr=5 pr=0 pw=0 time=20 us cost=2 size=0 card=4)'
STAT #364949696 id=6 cnt=2 pid=2 pos=2 obj=39004 op='INDEX RANGE SCAN T2_T1_ID (cr=5 pr=0 pw=0 time=22 us cost=1 size=0 card=1)'
STAT #364949696 id=7 cnt=2 pid=1 pos=2 obj=39002 op='TABLE ACCESS BY INDEX ROWID T2 (cr=2 pr=0 pw=0 time=7 us cost=2 size=2041 card=1)'
*** 2018-11-20 20:47:19.273
WAIT #364949696: nam='SQL*Net message from client' ela= 13617051 driver id=1111838976 #bytes=1 p3=0 obj#=6310 tim=386224843380
CLOSE #364949696:c=0,e=44,dep=0,type=0,tim=386224843833
=====================
PARSING IN CURSOR #364949696 len=55 dep=0 uid=62 oct=42 lid=62 tim=386224844060 hv=2217940283 ad='0' sqlid='06nvwn223659v'
alter session set events '10046 trace name context off'
END OF STMT
PARSE #364949696:c=0,e=123,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=0,tim=386224844059
EXEC #364949696:c=0,e=1340,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=0,tim=386224845780
优点:1.可以看出SQL语句对应的等待事件
2.如果SQL语句中有函数调用,SQL中有SQL,将会都被列出,无处遁形。
3.可以方便的看出处理的行数,产生的物理逻辑读。
4.可以方便的看出解析时间和执行时间。
5.可以跟踪整个程序包
缺陷: 1.步骤繁琐,比较麻烦
2.无法判断表被访问了多少次。
3.执行计划中的谓词部分不能清晰的展现出来。
第六种方式(awrsqrpt.sql工具)
步骤1:@?/rdbms/admin/awrsqrpt.sql
步骤2:选择你要的断点(begin snap 和end snap)
步骤3:输入你的sql_id
直接回车:
分别输入开始和结束的Snap Id:
输入sql_id即可:
最后会生成报表。
具体操作可参看:https://blog.csdn.net/Dongguabai/article/details/84309887
参考资料: