Oracle SQL_TRACE使用小结

一、关于基础表

Oracle 10G之前,启用AUTOTRACE功能需要手工创建plan_table表,创建脚本为$ORACLE_HOME/rdbms/admin/utlxplan.sql。但在10g中,已经默认创建了PLAN_TABLE$的基表,并以public用户创建了相应的同义词PUBLIC。

SQL> select owner,object_name,OBJECT_TYPE from dba_objects where object_name like '%PLAN_TABLE%';

OWNER OBJECT_NAME OBJECT_TYPE
------------------------------ -------------------- -------------------
SYS SQL_PLAN_TABLE_TYPE TYPE
PUBLIC SQL_PLAN_TABLE_TYPE SYNONYM
SYS PLAN_TABLE$ TABLE
PUBLIC PLAN_TABLE SYNONYM
EXFSYS EXF$PLAN_TABLE TABLE

SQL> select * from dba_synonyms where SYNONYM_NAME like '%PLAN_TABLE%';

OWNER SYNONYM_NAME TABLE_OWNER TABLE_NAME DB_LINK
-------------- ---------------------- ------------------------------ ------------------------------ --------
PUBLIC SQL_PLAN_TABLE_TYPE SYS SQL_PLAN_TABLE_TYPE
PUBLIC PLAN_TABLE SYS PLAN_TABLE$

从上面的结果可以看出,PLAN_TABLE正是基于PLAN_TABLE$的同义词。

二、关于plustrace角色

和Oracle9i一样,10g中plustrace角色默认也是disabled的。如果使用非授权用户打开Oracle trace功能会得到以下的错误。

SQL> conn hr/hr
Connected.
SQL> set autotrace trace
SP2-0618: Cannot find the Session Identifier. Check PLUSTRACE role is enabled
SP2-0611: Error enabling STATISTICS report

这时需要执行$ORACLE_HOME/sqlplus/admin/plustrce.sql脚本,手工创建plustrace角色。

SQL> @$ORACLE_HOME/sqlplus/admin/plustrce.sql;
SQL>
SQL> drop role plustrace;
drop role plustrace
*
ERROR at line 1:
ORA-01919: role 'PLUSTRACE' does not exist


SQL> create role plustrace;

Role created.

SQL> grant select on v_$sesstat to plustrace;

Grant succeeded.

SQL> grant select on v_$statname to plustrace;

Grant succeeded.

SQL> grant select on v_$mystat to plustrace;

Grant succeeded.

SQL> grant plustrace to dba with admin option;

Grant succeeded.

SQL> set echo off

接下来就可以手工将plustrace角色授予需要的角色或用户,或者直接将其授予public角色,这样所有public角色的用户都有使用autotrace功能的权限了。

SQL> grant plustrace to hr;

Grant succeeded.

SQL> conn hr/hr
Connected.
SQL> set autotrace trace

三、关于autotrace功能内部操作

默认的,在启用autotrace功能时Oracle另启用一个session,专门用于收集和输出统计信息。

SQL> set autotrace off
SQL> select sid,serial#,username from v$session where username is not null;

SID SERIAL# USERNAME
---------- ---------- ------------------------------
146 906 SYS
159 3 SYS
......

SQL> set autotrace on exp
SQL> select sid,serial#,username from v$session where username is not null;

SID SERIAL# USERNAME
---------- ---------- ------------------------------
129 6 SYSMAN
135 4 DBSNMP
136 356 SYSMAN
143 45 SYSMAN
145 10 SYSMAN
146 906 SYS
149 38 DBSNMP
159 3 SYS

8 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3733760267

--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 108 | 0 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 108 | 0 (0)| 00:00:01 |
|* 2 | FIXED TABLE FULL | X$KSUSE | 1 | 95 | 0 (0)| 00:00:01 |
|* 3 | FIXED TABLE FIXED INDEX| X$KSLED (ind:2) | 1 | 13 | 0 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("S"."KSUUDLNA" IS NOT NULL AND "S"."INST_ID"=USERENV('INSTANCE') AND
BITAND("S"."KSSPAFLG",1)<>0 AND BITAND("S"."KSUSEFLG",1)<>0)
3 - filter("S"."KSUSEOPC"="E"."INDX")

而收集统计信息的时候,则多出一个session。

SQL> set autotrace on stat
SQL> select sid,serial#,username from v$session where username is not null;

SID SERIAL# USERNAME
---------- ---------- ------------------------------
126 692 SYS
129 6 SYSMAN
135 4 DBSNMP
136 356 SYSMAN
143 45 SYSMAN
145 10 SYSMAN
146 906 SYS
149 38 DBSNMP
159 3 SYSITPUB

9 rows selected.

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
695 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
9 rows processed
SQL> select a.sid,a.serial#,a.username,b.pid,b.spid
2 from v$session a,v$process b
3 where a.paddr=b.addr and a.username is not null;

SID SERIAL# USERNAME PID SPID
---------- ---------- ------------------------------ ---------- ------------
159 3 SYS 15 4261
146 906 SYS 18 6977
126 692 SYS 18 6977
......

9 rows selected.

$ ps -ef|grep -v grep|grep 6977
oracle 6977 6976 0 21:22 ? 00:00:00 oraclerandy (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

四、关于DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION

其实我们更多的时候需要跟踪的其他用户的进程,而很多这样的用户可能没有被授予或者不允许授予plustrace角色。这时可以使用DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION过程来实现对进程的跟踪,该过程需要提供用户进程的sid和serial#。

SQL> select sid,serial# from v$session where username ='HR';

SID SERIAL#
---------- ----------
159 5

SQL> exec dbms_system.SET_SQL_TRACE_IN_SESSION(159,5,true);

PL/SQL procedure successfully completed.

SQL> select a.sid,a.serial#,a.username,b.pid,b.spid
2 from v$session a,v$process b
3 where a.paddr=b.addr and a.username='HR';

SID SERIAL# USERNAME PID SPID
---------- ---------- ------------------------------ ---------- ------------
159 5 HR 15 9080

回到用户HR的连接中执行SQL语句,然后使用tkprof工具格式化USER_DUMP_FILE目录中的跟踪文件。

$ tkprof randy_ora_9080.trc 9080.txt
$ more 9080.txt

......
select *
from
jobs


F| r KrYz0call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.01 0.02 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 6 0.00 0.04 6 18 0 38
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 10 0.02 0.06 6 18 0 38

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 55

Rows Row Source Operation
------- ---------------------------------------------------
19 TABLE ACCESS FULL JOBS (cr=9 pr=6 pw=0 time=42771 us)
......

从跟踪文件中,可以发现很多关于Oracle在实现用户需求时的内部操作,深入研究确实会有很多的收获。不过这里我们关心的是上面摘录的部分,可以看到select * from jobs执行计划和相关的统计信息。

五、使用会话级10046事件

除了上述的方法外,还可以使用会话级的10046事件来实现进程跟踪。

SQL> alter session set events '10046 trace name context forever, level 12';

SQL> alter session set events '10046 trace name context off';

如果用户没有alter session的权限,可以使用DBMS_SYSTEM.SET_EV过程来实现对用户进程的跟踪。

SQL> desc DBMS_SYSTEM

......
PROCEDURE SET_EV
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
SI BINARY_INTEGER IN
SE BINARY_INTEGER IN
EV BINARY_INTEGER IN
LE BINARY_INTEGER IN
NM VARCHAR2 IN
......

几个参数分别是进程sid,serial#,event name,level,username。

SQL> select sid,serial# from v$session where username ='HR';

SID SERIAL#
---------- ----------
154 298

SQL> exec dbms_system.set_ev(154,298,10046,12,'');

PL/SQL procedure successfully completed.

SQL> select a.sid,a.serial#,a.username,b.pid,b.spid
2 from v$session a,v$process b
3 where a.paddr=b.addr and a.username='HR';

SID SERIAL# USERNAME PID SPID
---------- ---------- ------------------------------ ---------- ------------
154 298 HR 15 9903

使用tkprof格式化跟踪文件,可以得到和第四部分相同的输出。

六、使用DBMS_MONITOR

DBMS_MONITOR包也非常的强大,可以提供基于客户ID、服务模块以及数据库级和会话级的跟踪和统计。这里使用SESSION_TRACE_ENABLE来实现数据库级的跟踪。

QL> desc dbms_monitor
......
PROCEDURE SESSION_TRACE_DISABLE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
SESSION_ID BINARY_INTEGER IN DEFAULT
SERIAL_NUM BINARY_INTEGER IN DEFAULT
PROCEDURE SESSION_TRACE_ENABLE
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
SESSION_ID BINARY_INTEGER IN DEFAULT
SERIAL_NUM BINARY_INTEGER IN DEFAULT
(Y*O0J~:?$nZ0 WAITS BOOLEAN IN DEFAULT
BINDS BOOLEAN IN DEFAULT
......

SQL> select a.sid,a.serial#,a.username,b.pid,b.spid
2 from v$session a,v$process b
3 where a.paddr=b.addr and a.username = 'HR';

SID SERIAL# USERNAME PID SPID
---------- ---------- ------------------------------ ---------- ------------
159 348 HR 18 12569

SQL> exec dbms_monitor.SESSION_TRACE_ENABLE(159,348);

PL/SQL procedure successfully completed.

SQL> exec dbms_monitor.SESSION_TRACE_DISABLE(159,348);

PL/SQL procedure successfully completed.ITPUB

使用这种方法也可以实现对会话的跟踪。

七、使用oradebug实现跟踪

oradebug是一个非常强大的工具,广泛的使用在设置debug事件和产生dumps。我们也可以通过这个工具,设置会话的10046事件,从而实现对会话的跟踪。说到底,还是10046事件的一种实现方式,但是由于它强大的功能本人对它非常的钟爱,所以单独列了出来。

接上面的实验,我们可以看到用户HR的PID为18,下面我们通过oradebug实现对该进程的跟踪。

SQL> oradebug SETORAPID 18
Unix process pid: 12569, image:
oracle@oracle (TNS V1-V3)

SQL> oradebug SESSION_EVENT 10046 trace name context forever,level 12;
Statement processed.

SQL> oradebug tracefile_name
/u01/oracle/admin/randy/udump/randy_ora_12569.trc

SQL> oradebug SESSION_EVENT 10046 trace name context off;
Statement processed.

你可能感兴趣的:(Oracle SQL)