查看 sql 执行计划的方法有许多种, 10046 事件就是其中的一种. 与其他查看 sql 执行计划不同, 当我们遇到比较复杂的 sql 语句, 我们可以通过 10046 跟踪 sql 得到执行计划中每一个步骤的逻辑读, 物理读以及花费的时间等. 这种细粒度的跟踪对于我们分析 sql 性能尤其有用.
10046:SQL到底是如何执行的:
10046 = 设置sql_trace=true; 10046 可以跟踪到等待事件&绑定变量; tkprof 只解读(格式化)10046的trace文件
10053:SQL为什么要这样执行:
将语句执行涉及到的与成本相关的信息展示出来; 有表的各个index的成本的罗列(index的访问成本),罗列访问表的成本,展示为何是这个执行计划,10053使用的很少的。
10046事件:
> 跟踪会话执行的SQL的情况
> 跟踪会话中的SQL的执行计划及等待事件
> 可以通过TKPROF,TRCA等工具格式化trc文件
打开10046事件跟踪:
alter session set events = '10046 trace name context forever,level 12';
关闭10046事件跟踪:
alter session set events '10046 trace name context off';
dump 控制文件结构:
alter session set events 'immediate trace name controlf level 12';
dump 数据文件头:
alter session set events 'immediate trace name file_hdrs level 12';
10053事件:
优化器输入、计算输出的协议,把决策过程日志写入跟踪文件,可以看出优化器的工作原理,选择最佳执行计划的原因。
打开10053事件跟踪:
alter session set events '10053 trace name context forever,level 1';
获得跟踪文件的位置:
SQL> oradebug setmypid
SQL> oradebug tracefile_name
关闭10053事件跟踪:
alter session set events '10053 trace name context off';
event 10053跟踪文件的内容:
> 优化语句相关表的查询块和对象标识符
> 考虑到的查询转换
> 缩写名称的注释
> 绑定变量的结果
> 优化器考虑到的参数(显式和隐式)
> 系统统计信息
> 表和索引的对象统计信息
> 单表访问路径和成本
> 执行计划
> 谓语信息
> 查询块的outline信息
一般来说, 使用 10046 事件得到 sql 执行计划的步骤如下:
1. 激活当前 session 10046 事件
2. 在当前 session 中执行 sql 语句
3. 关闭当前 session 10046 事件
执行完上述步骤后, 通常会自动生成一个 trace 文件. 在 oracle 11g 中, trace 文件一般放在$ORACLE_BASE/diag/rdbms/{database_name}/$ORACLE_SID/trace 目录下. 如果使用 oradebug 激活跟踪 10046后, 可以使用 oradebug tracefile_name 得到刚刚生成的 trace 文件的完整路径.
- NAME TYPE VALUE
- ------------------------------------ ----------- ------------------------------
- background_dump_dest string g:appdavidddiag dbmsdavid
- david race
刚刚提到的 oradebug 激活跟踪 10046 事件, 我想大部分 dba 都会使用. oradebug 是个功能强大非常好用的工具, 使用 oradebug help 将会看到它的功能很多
- SQL> oradebug help
使用 oradebug 跟踪 10046 命令如下:
- SQL> oradebug setmypid
- Statement processed.
- // 激活 10046 事件
- SQL> oradebug event 10046 trace name context forever,level 12;
- Statement processed.
- SQL> select /*+ leading(t3) use_merge(t4) */ *
- 2 from t3, t4
- 3 where t3.id = t4.t3_id and t3.n = 1100;
- 10 rows selected.
- // 在当前 session 关闭 10046 事件
- SQL> oradebug event 10046 trace name context off;
- Statement processed.
- // 使用 oradebug tracefile_name 可以直接看到生成的 trace 文件的位置
- SQL> oradebug tracefile_name;
- g:appdavidddiag dbmsdaviddavid racedavid_ora_2176.trc
其中, 10046 按照收集信息的内容分为以下等级:
Level 0 | 停用SQL跟踪,相当于SQL_TRACE=FALSE |
Level 1 | 标准SQL跟踪,相当于SQL_TRACE=TRUE |
Level 4 | 在level 1的基础上增加绑定变量的信息 |
Level 8 | 在level 1的基础上增加等待事件的信息 |
Level 12 | 在level 1的基础上增加绑定变量和等待事件的信息 |
分析读懂 trace 文件
现在我们打开 g:appdavidddiag dbmsdaviddavid racedavid_ora_2176.trc 看看生成的 trace 文件的内容
- <pre name="code" class="sql"><pre name="code" class="sql"><pre name="code" class="sql"><pre name="code" class="sql" style="font-size:14px;">PARSING IN CURSOR #22 len=92 dep=0 uid=0 oct=3 lid=0 tim=900460923321 hv=1624778336 ad='34671d90' sqlid='g0rdyg9hdh9m0'
- select /*+ leading(t3) use_merge(t4) */ *
- from t3, t4
- where t3.id = t4.t3_id and t3.n = 1100
- END OF STMT
- PARSE #22:c=0,e=10777,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=3831111046,tim=900460923319
- EXEC #22:c=0,e=29,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3831111046,tim=900460923482
- WAIT #22: nam='SQL*Net message to client' ela= 2 driver id=1111838976 #bytes=1 p3=0 obj#=-1 tim=900460923512
- FETCH #22:c=15625,e=23922,p=0,cr=119,cu=0,mis=0,r=1,dep=0,og=1,plh=3831111046,tim=900460947462
- WAIT #22: nam='SQL*Net message from client' ela= 221 driver id=1111838976 #bytes=1 p3=0 obj#=-1 tim=900460947755
- WAIT #22: nam='SQL*Net message to client' ela= 2 driver id=1111838976 #bytes=1 p3=0 obj#=-1 tim=900460947803
- FETCH #22:c=0,e=71,p=0,cr=0,cu=0,mis=0,r=9,dep=0,og=1,plh=3831111046,tim=900460947864
- STAT #22 id=1 cnt=10 pid=0 pos=1 obj=0 op='MERGE JOIN (cr=119 pr=0 pw=0 time=28 us cost=193 size=1280 card=10)'
- STAT #22 id=2 cnt=1 pid=1 pos=1 obj=0 op='SORT JOIN (cr=15 pr=0 pw=0 time=0 us cost=6 size=63 card=1)'
- STAT #22 id=3 cnt=1 pid=2 pos=1 obj=83550 op='TABLE ACCESS FULL T3 (cr=15 pr=0 pw=0 time=0 us cost=5 size=63 card=1)'
- STAT #22 id=4 cnt=10 pid=1 pos=2 obj=0 op='SORT JOIN (cr=104 pr=0 pw=0 time=11 us cost=187 size=650000 card=10000)'
- STAT #22 id=5 cnt=10000 pid=4 pos=1 obj=83552 op='TABLE ACCESS FULL T4 (cr=104 pr=0 pw=0 time=8603 us cost=29 size=650000 card=10000)'
从上面的 trace 文件我们可以看出 sql 语句经过了 parse(解析) -> exec(执行) -> fetch(从游标中获取数据) 几个过程, 其中第一句说明了当前跟踪执行的 sql 语句的概况,比如使用游标号, sql 语句的长度, 递归深度等等基本信息:
- PARSING IN CURSOR #22 len=92 dep=0 uid=0 oct=3 lid=0 tim=900460923321 hv=1624778336 ad='34671d90' sqlid='g0rdyg9hdh9m0'
cursor | cursor number |
len | sql 语句长度 |
dep | sql 语句递归深度 |
uid | user id |
oct | oracle command type |
lid | privilege user id |
tim | timestamp,时间戳 |
hv | hash id |
ad | sql address 地址, 用在 v$sqltext |
sqlid | sql id |
接着, 下面的语句说明了 sql 语句具体的执行过程以及每一个步骤消耗 CPU 的时间等性能指标
- PARSE #22:c=0,e=10777,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,plh=3831111046,tim=900460923319
- EXEC #22:c=0,e=29,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3831111046,tim=900460923482
- FETCH #22:c=15625,e=23922,p=0,cr=119,cu=0,mis=0,r=1,dep=0,og=1,plh=3831111046,tim=900460947462
c | CPU 消耗的时间 |
e | Elapsed time |
p | number of physical reads 物理读的次数 |
cr | number of buffers retrieved for CR reads 逻辑读的数据块 |
cu | number of buffers retrieved in current mode (current 模式读取的数据块) |
mis | cursor missed in the cache 库缓存中丢失的游标, 硬解析次数 |
r | number of rows processed 处理的行数 |
dep | 递归深度 |
og | optimizer mode 【1:all_rows, 2:first_rows, 3:rule, 4:choose】 |
plh | plan hash value |
tim | timestamp 时间戳 |
以及执行过程中的发生的等待事件
- WAIT #22: nam='SQL*Net message to client' ela= 2 driver id=1111838976 #bytes=1 p3=0 obj#=-1 tim=900460923512
nam | an event that we waited for 等待事件 |
ela | 此操作消耗的时间 |
p3 | block 块号 |
trm | timestamp 时间戳 |
最后显示的是该游标的执行计划
- STAT #22 id=1 cnt=10 pid=0 pos=1 obj=0 op='MERGE JOIN (cr=119 pr=0 pw=0 time=28 us cost=193 size=1280 card=10)'
- STAT #22 id=2 cnt=1 pid=1 pos=1 obj=0 op='SORT JOIN (cr=15 pr=0 pw=0 time=0 us cost=6 size=63 card=1)'
- STAT #22 id=3 cnt=1 pid=2 pos=1 obj=83550 op='TABLE ACCESS FULL T3 (cr=15 pr=0 pw=0 time=0 us cost=5 size=63 card=1)'
- STAT #22 id=4 cnt=10 pid=1 pos=2 obj=0 op='SORT JOIN (cr=104 pr=0 pw=0 time=11 us cost=187 size=650000 card=10000)'
- STAT #22 id=5 cnt=10000 pid=4 pos=1 obj=83552 op='TABLE ACCESS FULL T4 (cr=104 pr=0 pw=0 time=8603 us cost=29 size=650000 card=10000
cnt | 当前行源返回的行数 |
pid | parent id of this row source 当前行源的父结点 id |
pos | position in explain plan 执行计划的位置 |
obj | object id of row source (if this is a base object) |
op | the row source access operation |
例如, 执行步骤 merge join 消耗的逻辑读为 119, 物理读为 0, 耗费的时间为 28 us, 成本 cost 193,返回 10 条记录
使用 tkprof 命令翻译 trace 文件
我们也可以使用 tkprof 命令对 trace 文件进行翻译,得到一个容易理解的 trace 汇总报表文件
- C:Documents and Settingsdavidd> tkprof g:appdavidddiag dbmsdaviddavid racedavid_ora_2176.trc d: race.trc
- TKPROF: Release 11.2.0.1.0 - Development on Thu Dec 18 18:51:44 2014
- Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
tkprof 翻译的 trace 文件的汇总报表如下:
- Trace file: g:appdavidddiag dbmsdaviddavid racedavid_ora_2176.trc
- Sort options: default
- ********************************************************************************
- count = number of times OCI procedure was executed
- cpu = cpu time in seconds executing
- elapsed = elapsed time in seconds executing
- disk = number of physical reads of buffers from disk
- query = number of buffers gotten for consistent read
- current = number of buffers gotten in current mode (usually for update)
- rows = number of rows processed by the fetch or execute call
- ********************************************************************************
- select /*+ leading(t3) use_merge(t4) */ *
- from t3, t4
- where t3.id = t4.t3_id and t3.n = 1100
- call count cpu elapsed disk query current rows
- ------- ------ -------- ---------- ---------- ---------- ---------- ----------
- Parse 1 0.00 0.00 0 0 0 0
- Execute 1 0.00 0.00 0 0 0 0
- Fetch 2 0.00 0.00 0 119 0 10
- ------- ------ -------- ---------- ---------- ---------- ---------- ----------
- total 4 0.00 0.00 0 119 0 10
- Misses in library cache during parse: 1
- Optimizer mode: ALL_ROWS
- Parsing user id: SYS
- Rows Row Source Operation
- ------- ---------------------------------------------------
- 10 MERGE JOIN (cr=119 pr=0 pw=0 time=0 us cost=193 size=1280 card=10)
- 1 SORT JOIN (cr=15 pr=0 pw=0 time=0 us cost=6 size=63 card=1)
- 1 TABLE ACCESS FULL T3 (cr=15 pr=0 pw=0 time=0 us cost=5 size=63 card=1)
- 10 SORT JOIN (cr=104 pr=0 pw=0 time=0 us cost=187 size=650000 card=10000)
- 10000 TABLE ACCESS FULL T4 (cr=104 pr=0 pw=0 time=8733 us cost=29 size=650000 card=10000)
- Elapsed times include waiting on following events:
- Event waited on Times Max. Wait Total Waited
- ---------------------------------------- Waited ---------- ------------
- SQL*Net message to client 2 0.00 0.00
- SQL*Net message from client 2 20.23 20.23
- ********************************************************************************
- OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS
- call count cpu elapsed disk query current rows
- ------- ------ -------- ---------- ---------- ---------- ---------- ----------
- Parse 1 0.00 0.00 0 0 0 0
- Execute 1 0.00 0.00 0 0 0 0
- Fetch 2 0.00 0.00 0 119 0 10
- ------- ------ -------- ---------- ---------- ---------- ---------- ----------
- total 4 0.00 0.00 0 119 0 10
- Misses in library cache during parse: 1
- Elapsed times include waiting on following events:
- Event waited on Times Max. Wait Total Waited
- ---------------------------------------- Waited ---------- ------------
- SQL*Net message to client 3 0.00 0.00
- SQL*Net message from client 3 20.23 30.20
- OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS
- call count cpu elapsed disk query current rows
- ------- ------ -------- ---------- ---------- ---------- ---------- ----------
- Parse 0 0.00 0.00 0 0 0 0
- Execute 0 0.00 0.00 0 0 0 0
- Fetch 0 0.00 0.00 0 0 0 0
- ------- ------ -------- ---------- ---------- ---------- ---------- ----------
- total 0 0.00 0.00 0 0 0 0
- Misses in library cache during parse: 0
- 1 user SQL statements in session.
- 0 internal SQL statements in session.
- 1 SQL statements in session.
- ********************************************************************************
- Trace file: g:appdavidddiag dbmsdaviddavid racedavid_ora_2176.trc
- Trace file compatibility: 11.1.0.7
- Sort options: default
- 1 session in tracefile.
- 1 user SQL statements in trace file.
- 0 internal SQL statements in trace file.
- 1 SQL statements in trace file.
- 1 unique SQL statements in trace file.
- 122 lines in trace file.
- 0 elapsed seconds in trace file.
其中,Misses in library cache during parse :1 意思是解析的时候库缓存丢失游标, 也就是说发生了一次硬解析
参考: http://www.eygle.com/archives/2005/10/aeearaw_traceia.html
http://czmmiao.iteye.com/blog/1493765 tkprof 的使用
http://czmmiao.iteye.com/blog/1493933 读懂trace