基于以前开发的一个用于监控线程的CPU使用状况的小工具TopShow我开发了一个用于追蹤Oracle内部函数调用的追蹤器——OraTracer 你可以用该工具追蹤监控Oracle多个内部函数的调用情况还可以尝试探测函数的输入参数的值也可以打印追蹤点被触发时的调用堆栈追蹤可以设置在整个Oracle进程的级别也可以设置在某个线程以追蹤特定的会话
例子
捕获oracle整个实例中被执行的SQL语句
首先在与可执行文件相同的目录下设置追蹤点文件TracePointstxt内容如下
_opiprs *
_rpisplu *
_kprbprs
与函数名用空格相隔的数值为探测的参数数量如果再加上*N则表示尝试将双字节数字作为指针对待递归获取其执行的值后面的数字为递归深度例如对于第一个追蹤点函数名为_opiprs探测个参数递归探测指针数据的深度为
注意#为注释符
然后从进程列表中选择ORACLEEXE不要选择任何线程
最后点击Trace按钮一旦有语句被上述函数调用你就可以从监控窗口看到这些语句
SQL代码
…
[ ::]User call: _rpisplu (TID: )
[Args()]:
select privilege#level from sysauth$ connect by grantee#=prior privilege# and privilege#> start with grantee#=: and privilege#>
×(=>NULL)
[ ::]User call: _rpisplu (TID: )
[Args()]:
alter session set NLS_LANGUAGE=AMERICAN NLS_TERRITORY=AMERICA NLS_CURRENCY=$ NLS_ISO_CURRENCY=AMERICA NLS_NUMERIC_CHARACTERS= NLS_DATE_FORMAT=DDMONRR NLS_DATE_LANGUAGE=AMERICAN NLS_SORT=BINARY
xd(=>NULL)
[ ::]User call: _opiprs (TID: )
[Args()]:
×cce(=>×)
alter session set NLS_LANGUAGE=AMERICAN NLS_TERRITORY=AMERICA NLS_CURRENCY=$ NLS_ISO_CURRENCY=AMERICA NLS_NUMERIC_CHARACTERS= NLS_DATE_FORMAT=DDMONRR NLS_DATE_LANGUAGE=AMERICAN NLS_SORT=BINARY
xd(=>NULL)
×bfe(=>×)
[ ::]User call: _rpisplu (TID: )
[Args()]:
×(=>NULL)
×(=>NULL)
select sysdate + / ( * ) from dual
×(=>NULL)
[ ::]User call: _rpisplu (TID: )
[Args()]:
×(=>NULL)
×(=>NULL)
DECLARE job BINARY_INTEGER := :job; next_date DATE := :mydate; broken BOOLEAN := FALSE; BEGIN EMD_MAINTENANCEEXECUTE_EM_DBMS_JOB_PROCS(); :mydate := next_date; IF broken THEN :b := ; ELSE :b := ; END IF; END;
xd(=>NULL)
…
点击Stop按钮停止追蹤
例子 :
理解SQL是如何被执行计划驱动执行的
我们知道查询计划实际上就是驱动Oracle通过特定函数及顺序来获取数据我们可以通过追蹤这些函数来理解执行计划
首先下载以下文件解压重命名为TracePointstxt放到OraTracerexe所在目录
然后获取到你需要追蹤的会话的SPID
SQL代码
HELLODBACOM>select distinct spid from v$mystat m v$session s v$process p where ssid=msid and spaddr=paddr;
SPID
————
从进程列表中选择ORACLEEXE => 从线程列表中选择TID为的线程 => 点击Trace按钮
在被追蹤的会话中执行一条语句
SQL代码
HELLODBACOM>select * from demot_test where owner=DEMO and object_name like T_TEST%;
OWNER OBJECT_NAME SUBOBJECT_NAME OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED
LAST_DDL_TIME TIMESTAMP STATUS T G S
—————————— —————————— —————————— ——— ————– —————— ———–
——– —————— —————— ——
DEMO T_TEST AAA TABLE
:: :: ::: VALID N N N
注意为了避免回滚调用也被追蹤你最好在追蹤之前先运行一次该语句
我们可以从追蹤窗口看到数据fetch调用情况
SQL代码
[ ::]User call: _qertbFetchByRowID (TID: )
[ ::]User call: _qerixtFetch (TID: )
[ ::]User call: _qertbFetchByRowID (TID: )
[ ::]User call: _qerixtFetch (TID: )
有了这样的追蹤记录你可以尝试将他们与执行计划中节点映射
SQL代码
HELLODBACOM>select * from demot_test where owner=DEMO and object_name like T_TEST%;
Execution Plan
———————————————————
Plan hash value:
——————————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————————
| | SELECT STATEMENT | | | | ()| :: |
| | TABLE ACCESS BY INDEX ROWID| T_TEST | | | ()| :: | ==> _qertbFetchByRowID
|* | INDEX RANGE SCAN | T_TEST_IDX | | | ()| :: | ==> _qerixtFetch
例子 :
打印某个特定函数被调用时的线程调用堆栈
我们这里追蹤_kkeAdjSingTabCard设置追蹤点
SQL代码
_kkeAdjSingTabCard*
函数名后的*N指定输出的调用个数为无限制
然后获取到你需要追蹤的会话的SPID
SQL代码
HELLODBACOM>select distinct spid from v$mystat m v$session s v$process p where ssid=msid and spaddr=paddr;
SPID
————
从进程列表中选择ORACLEEXE => 从线程列表中选择TID为的线程 => 点击Trace按钮
在被追蹤的会话中解释一条语句
SQL代码
HELLODBACOM>explain plan for select /*+full(t)*/ count(*) from demot_test t;
Explained
我们就可以从监控窗口获取到该函数被调用时的整个调用堆栈的情况
SQL代码
[ ::]User call: _kkeAdjSingTabCard (TID: )
Call Stacks():
× (ORACLEEXE!_kkoitbp+)
×cd (ORACLEEXE!_kkoijbad+)
×db (ORACLEEXE!_kkoCopyPreds+)
×eea (ORACLEEXE!_kkosta+)
×dfc (ORACLEEXE!__PGOSF__apaRequestBindCapture+)
×d (ORACLEEXE!_apagcp+)
×dc (ORACLEEXE!_apafbr+)
xea (ORACLEEXE!_opitcaNcp+)
×beb (ORACLEEXE!_kksMinimalTypeCheck+)
×d (ORACLEEXE!_rpidrus+)
×bce (ORACLEEXE!_kksSetNLSHandle+)
×e (ORACLEEXE!_kxsReleaseRuntimeLock+)
× (ORACLEEXE!_kkscbt+)
×ecf (ORACLEEXE!_kksParseCursor+)
×fb (ORACLEEXE!_kksxsccompat+)
×e (ORACLEEXE!_opibrp+)
×cded (ORACLEEXE!_kpodrd+)
×cbac (ORACLEEXE!_kpocrs+)
×e (ORACLEEXE!_opirip+)
×feff (oracommondll!_ttcpro+)
×a (ORACLEEXE!_opiodr+)
× (ORACLEEXE!_opiino+)
×e (ORACLEEXE!_opirip+)
×e (ORACLEEXE!_opidcl+)
×a (ORACLEEXE!_ksdwri+)
× (ORACLEEXE!_ssthrnfy+)
× (ORACLEEXE!_opimai_init+)
× (ORACLEEXE!_osnsoiint+)
×cb (KERNELdll!GetModuleFileNameA+)
[Args()]:
×ed
×eda
×a
×