SQL Trace

来源:互联网 发布:3d游戏美工 编辑:程序博客网 时间:2024/06/05 18:28
一、关于基础表

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。

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来实现数据库级的跟踪。

SQL> 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
 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.

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

七、使用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.
0 0