基于以前开发的一个用于监控线程的CPU使用状况的小工具,TopShow,我开发了一个用于追踪Oracle内部函数调用的追踪器——OraTracer. 你可以用该工具追踪监控Oracle多个内部函数的调用情况,还可以尝试探测函数的输入参数的,也可以打印追踪点被触发时的调用堆
基于以前开发的一个用于监控线程的CPU使用状况的小工具,TopShow,我开发了一个用于追踪Oracle内部函数调用的追踪器——OraTracer. 你可以用该工具追踪监控Oracle多个内部函数的调用情况,还可以尝试探测函数的输入参数的值,也可以打印追踪点被触发时的调用堆栈。追踪可以设置在整个Oracle进程的级别,也可以设置在某个线程以追踪特定的会话。例子 1:
捕获oracle整个实例中被执行的SQL语句。
首先,在与可执行文件相同的目录下设置追踪点文件”TracePoints.txt”,内容如下:
_opiprs 6*1
_rpisplu 6*2
_kprbprs 6
与函数名用空格相隔的数值为探测的参数数量,如果再加上”*N”,则表示尝试将双字节数字作为指针对待,递归获取其执行的值,后面的数字为递归深度。例如,对于第一个追踪点,函数名为”_opiprs”,探测6个参数,递归探测指针数据的深度为1。
注意:”#”为注释符。
然后从进程列表中选择”ORACLE.EXE”,不要选择任何线程:
最后,点击”Trace”按钮。一旦有语句被上述函数调用,你就可以从监控窗口看到这些语句:
SQL代码
…
[2010-5-28 3:53:23.426]User call: _rpisplu (TID: 5276)
[Args(6)]:
6
0
0
“select privilege#,level from sysauth$ connect by grantee#=prior privilege# and privilege#>0 start with grantee#=:1 and privilege#>0“
0×84(=>NULL)
0
[2010-5-28 3:53:23.442]User call: _rpisplu (TID: 5276)
[Args(6)]:
6
0
0
“alter session set NLS_LANGUAGE=’AMERICAN’ NLS_TERRITORY=’AMERICA’ NLS_CURRENCY=’$’ NLS_ISO_CURRENCY=’AMERICA’ NLS_NUMERIC_CHARACTERS=’.,’ NLS_DATE_FORMAT=’DD-MON-RR’ NLS_DATE_LANGUAGE=’AMERICAN’ NLS_SORT=’BINARY’“
0xd4(=>NULL)
0
[2010-5-28 3:53:23.473]User call: _opiprs (TID: 5276)
[Args(6)]:
0×70cce00(=>0×4000000)
“alter session set NLS_LANGUAGE=’AMERICAN’ NLS_TERRITORY=’AMERICA’ NLS_CURRENCY=’$’ NLS_ISO_CURRENCY=’AMERICA’ NLS_NUMERIC_CHARACTERS=’.,’ NLS_DATE_FORMAT=’DD-MON-RR’ NLS_DATE_LANGUAGE=’AMERICAN’ NLS_SORT=’BINARY’“
0xd5(=>NULL)
0×4bfe214(=>0×18)
0
6
[2010-5-28 3:53:23.504]User call: _rpisplu (TID: 5276)
[Args(6)]:
3
0×20(=>NULL)
0×20(=>NULL)
“select sysdate + 1 / (24 * 60) from dual“
0×28(=>NULL)
1
[2010-5-28 3:53:23.520]User call: _rpisplu (TID: 5276)
[Args(6)]:
5
0×20(=>NULL)
0×20(=>NULL)
“DECLARE job BINARY_INTEGER := :job; next_date DATE := :mydate; broken BOOLEAN := FALSE; BEGIN EMD_MAINTENANCE.EXECUTE_EM_DBMS_JOB_PROCS(); :mydate := next_date; IF broken THEN :b := 1; ELSE :b := 0; END IF; END; “
0xd5(=>NULL)
0
…
点击”Stop”按钮,停止追踪。
例子 2:
理解SQL是如何被执行计划驱动执行的。
我们知道,查询计划实际上就是驱动Oracle通过特定函数及顺序来获取数据。我们可以通过追踪这些函数来理解执行计划。
首先下载以下文件,解压,重命名为”TracePoints.txt”,放到OraTracer.exe所在目录:
http://www.HelloDBA.com/download/TracePoints_ALL_Query_Calls.zip
然后获取到你需要追踪的会话的SPID:
SQL代码
HELLODBA.COM>select distinct spid from v$mystat m, v$session s, v$process p where s.sid=m.sid and s.paddr=p.addr;
SPID
————
11076
从进程列表中选择ORACLE.EXE => 从线程列表中选择TID为11076的线程 => 点击”Trace”按钮
在被追踪的会话中执行一条语句:
SQL代码
HELLODBA.COM>select * from demo.t_test1 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_TEST1 AAA 97819 97819 TABLE 2007-06-07
13:48:08 2007-06-07 13:48:08 2007-06-07:13:48:08 VALID N N N
注意:为了避免回滚调用也被追踪,你最好在追踪之前先运行一次该语句。
我们可以从追踪窗口看到数据fetch调用情况:
SQL代码
[2010-5-28 6:28:29.649]User call: _qertbFetchByRowID (TID: 11076)
[2010-5-28 6:28:29.711]User call: _qerixtFetch (TID: 11076)
[2010-5-28 6:28:29.727]User call: _qertbFetchByRowID (TID: 11076)
[2010-5-28 6:28:29.727]User call: _qerixtFetch (TID: 11076)
有了这样的追踪记录,你可以尝试将他们与执行计划中节点映射:SQL代码
HELLODBA.COM>select * from demo.t_test1 where owner=‘DEMO’ and object_name like ‘T_TEST%’;
Execution Plan
———————————————————-
Plan hash value: 698582444
——————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————————-
| 0 | SELECT STATEMENT | | 5 | 495 | 4 (0)| 00:00:04 |
| 1 | TABLE ACCESS BY INDEX ROWID| T_TEST1 | 5 | 495 | 4 (0)| 00:00:04 | ==> _qertbFetchByRowID
|* 2 | INDEX RANGE SCAN | T_TEST_IDX7 | 5 | | 1 (0)| 00:00:02 | ==> _qerixtFetch
例子 3:
打印某个特定函数被调用时的线程调用堆栈。
我们这里追踪”_kkeAdjSingTabCard”。设置追踪点:
SQL代码
_kkeAdjSingTabCard*-1 6
函数名后的”*N”指定输出的调用个数,-1为无限制。
然后获取到你需要追踪的会话的SPID:
SQL代码
HELLODBA.COM>select distinct spid from v$mystat m, v$session s, v$process p where s.sid=m.sid and s.paddr=p.addr;
SPID
————
11076
从进程列表中选择ORACLE.EXE => 从线程列表中选择TID为11076的线程 => 点击”Trace”按钮
在被追踪的会话中解释一条语句:
SQL代码
HELLODBA.COM>explain plan for select /*+full(t)*/ count(*) from demo.t_test2 t;
Explained.
我们就可以从监控窗口获取到该函数被调用时的整个调用堆栈的情况:
SQL代码
[2010-5-28 6:51:55.591]User call: _kkeAdjSingTabCard (TID: 11076)
Call Stacks(-1):
0×1460029 (ORACLE.EXE!_kkoitbp+757)
0×144c44d (ORACLE.EXE!_kkoijbad+8869)
0×1445d8b (ORACLE.EXE!_kkoCopyPreds+851)
0×143ee0a (ORACLE.EXE!_kkosta+1694)
0×1d17f6c (ORACLE.EXE!__PGOSF443__apaRequestBindCapture+156)
0×1d18398 (ORACLE.EXE!_apagcp+388)
0×1d1683c (ORACLE.EXE!_apafbr+464)
0xea6682 (ORACLE.EXE!_opitcaNcp+1450)
0×5b4eb0 (ORACLE.EXE!_kksMinimalTypeCheck+20)
0×84d939 (ORACLE.EXE!_rpidrus+429)
0×5b8ce8 (ORACLE.EXE!_kksSetNLSHandle+5888)
0×87732e (ORACLE.EXE!_kxsReleaseRuntimeLock+1366)
0×831815 (ORACLE.EXE!_kkscbt+7237)
0×82e3cf (ORACLE.EXE!_kksParseCursor+2099)
0×82f1b8 (ORACLE.EXE!_kksxsccompat+148)
0×201683e (ORACLE.EXE!_opibrp+1970)
0×13cd5ed (ORACLE.EXE!_kpodrd+237)
0×13cba7c (ORACLE.EXE!_kpocrs+780)
0×85174e (ORACLE.EXE!_opirip+1102)
0×60feff90 (oracommon10.dll!_ttcpro+1276)
0×850a69 (ORACLE.EXE!_opiodr+1017)
0×1221350 (ORACLE.EXE!_opiino3+1092)
0×85174e (ORACLE.EXE!_opirip+1102)
0×420e58 (ORACLE.EXE!_opidcl+824)
0×42164a (ORACLE.EXE!_ksdwri+50)
0×401171 (ORACLE.EXE!_ssthrnfy+117)
0×401061 (ORACLE.EXE!_opimai_init+97)
0×401905 (ORACLE.EXE!_osnsoiint+713)
0×7c80b729 (KERNEL32.dll!GetModuleFileNameA+442)
[Args(6)]:
0×81e58d0
0×81e5da8
0
0×40a03000
0×8559500
0已抢65582个
抢已抢30295个
抢已抢16667个
抢已抢8447个
抢已抢10928个
抢已抢22320个
抢