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 SYS
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
call 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。