1. 程式人生 > 其它 >Oracle 11g R2效能優化 SQL TRACE--轉發

Oracle 11g R2效能優化 SQL TRACE--轉發

目錄


正文

作為Oracle官方自帶的一種基本效能診斷工具,SQL Trace可以用來評估當前正在執行的SQL語句的效率,同時為該語句生成統計資訊等,並儲存這些資訊到指定路徑下的跟蹤檔案(trace)當中。SQL Trace會將一條SQL語句或者PL/SQL包執行過程全部輸出到跟蹤檔案(trace)當中,可以通過分析跟蹤檔案(trace)來分析SQL語句的執行效率並進行效能診斷與優化。

通常來說trace檔案的內容不易於理解與閱讀,Oracle官方還提供了工具tkprof

對trace檔案進行格式化處理,本文不討論tkprof工具的使用。之前在工作中也有使用過SQL Trace進行SQL語句的跟蹤診斷,但都沒有進行完整的總結,本文就SQL Trace工具的使用進行梳理。

回到頂部

環境準備

  1. 作業系統(OS):CentOS Linux release 7.5.1804 (Core)
  2. 資料庫版本(Oracle Database):Oracle Database 11g R2(11.2.0.4.0)

同時配置了示例SCHEMA和解鎖了使用者SCOTTHR

回到頂部

跟蹤方式

開啟SQL Trace有如下幾種場景與方式:

  1. 當前會話開啟跟蹤本會話;
  2. 當前會話開啟跟蹤其他會話;
  3. 使用DBMS_MONITOR包來開啟跟蹤;
  4. 根據登入觸發器來開啟跟蹤。
回到頂部

當前會話跟蹤

最簡單的方法是在SQL*PLUS當中執行如下語句:

  • 開啟:
-- 配置trace檔案的識別符號便於尋找定位
SYS@dbabd> alter session set tracefile_identifier = dbabd;

-- 開啟當前會話跟蹤
SYS@dbabd> alter session set sql_trace = true;

通過執行以上語句就開啟了當前會話的跟蹤,trace檔案位於 $ORACLE_BASE/diag/rdbms/dbabd/dbabd/trace目錄下:

$ pwd
/data/app/oracle/diag/rdbms/dbabd/dbabd/trace
$ ls *DBABD*
dbabd_ora_27978_DBABD.trc  dbabd_ora_27978_DBABD.trm

以上得到trace檔案當中並不包含繫結變數值,也不包含等待事件資訊,如果需要這些資訊,可以使用DBMS_SESSION包來開啟跟蹤,前提是使用者必須有ALTER SESSION許可權,否則會報ORA-01031: insufficient privileges錯誤。關於DBMS_SESSION包的用法可以參考官方文件:DBMS_SESSION

如果事先沒有配置trace檔案的識別符號,則可以通過以下語句進行定位:

  • 定位:
-- 語句
select tracefile
  from v$session s
  join v$process p
    on p.addr = s.paddr
 where s.audsid = USERENV('SESSIONID');

-- 結果
SYS@dbabd> select tracefile
  2    from v$session s
  3    join v$process p
  4      on p.addr = s.paddr
  5   where s.audsid = USERENV('SESSIONID');

TRACEFILE
----------------------------------------------------------------------------------------------------
/data/app/oracle/diag/rdbms/dbabd/dbabd/trace/dbabd_ora_27978_DBABD.trc

有時需要確認當前會話是否開啟了跟蹤,可以使用如下語句查詢:

  • 查詢:
-- 語句
select s.sql_trace,
       s.sql_trace_waits,
       s.sql_trace_binds,
       traceid,
       tracefile
  from v$session s
  join v$process p
    on p.addr = s.paddr
 where s.audsid = USERENV('SESSIONID');

-- 結果
SYS@dbabd> select s.sql_trace,
  2         s.sql_trace_waits,
  3         s.sql_trace_binds,
  4         traceid,
  5         tracefile
  6    from v$session s
  7    join v$process p
  8      on p.addr = s.paddr
  9   where s.audsid = USERENV('SESSIONID');

SQL_TRACE  SQL_TRACE_WAITS SQL_TRACE_BINDS TRACEID    TRACEFILE
---------- --------------- --------------- ---------- ------------------------------------------------------------
ENABLED   FALSE           FALSE           DBABD      /data/app/oracle/diag/rdbms/dbabd/dbabd/trace/dbabd_ora_2797
                                                      8_DBABD.trc

如果需要關閉當前會話跟蹤,則執行如下語句:

  • 關閉
SYS@dbabd> alter session set sql_trace = false;
回到頂部

其他會話跟蹤

如果是通過當前會話開啟對其他會話的跟蹤,一般都由DBA通過SYS使用者操作,可以使用DBMS_SYSTEM包當中一個儲存過程SET_SQL_TRACE_IN_SESSION,前提是需要獲取到會話的SIDSERIAL#

  • 檢視DBMS_SYSTEM包當中的結構
SYS@dbabd> 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

…………省略…………

PROCEDURE SET_SQL_TRACE_IN_SESSION
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SID                            NUMBER                  IN
 SERIAL#                        NUMBER                  IN
 SQL_TRACE                      BOOLEAN                 IN
  • 獲取其他會話的SIDSERIAL#
SYS@dbabd> select sid,SERIAL#,username from v$session where username is not null;

       SID    SERIAL# USERNAME
---------- ---------- ------------------------------------------------------------------------------------------
       125         17 SYS
       141         45 SCOTT

實際環境當中可能出現同一個使用者有多個會話存在,需要根據v$session檢視當中的其他選項進行判斷,這裡假設只有一個SCOTT使用者會話。

  • 開啟對SCOTT使用者會話的跟蹤
SYS@dbabd> begin
  2    dbms_system.SET_SQL_TRACE_IN_SESSION(SID => 141,
  3                                         SERIAL# => 45,
  4                                         SQL_TRACE => true
  5    );
  6  end;
  7  /

PL/SQL procedure successfully completed.

或

SYS@dbabd> exec dbms_system.SET_SQL_TRACE_IN_SESSION(141,45,true);

PL/SQL procedure successfully completed.
  • 定位跟蹤的trace檔案
SYS@dbabd> select s.sql_trace,
  2         s.sql_trace_waits,
  3         s.sql_trace_binds,
  4         traceid,
  5         tracefile
  6    from v$session s
  7    join v$process p
  8      on p.addr = s.paddr
  9   where s.sid = 141;

SQL_TRACE  SQL_TRACE_WAITS SQL_TRACE_BINDS TRACEID    TRACEFILE
---------- --------------- --------------- ---------- ------------------------------------------------------------
ENABLED    FALSE           FALSE           SCOTT      /data/app/oracle/diag/rdbms/dbabd/dbabd/trace/dbabd_ora_1014
                                                      _SCOTT.trc
  • 關閉對SCOTT使用者會話的跟蹤
SYS@dbabd> exec dbms_system.SET_SQL_TRACE_IN_SESSION(141,45,false);

PL/SQL procedure successfully completed.
回到頂部

DBMS_MONITOR包跟蹤

無論是跟蹤當前會話或者其他會話都可以採用DBMS_MONITOR包當中的SESSION_TRACE_ENABLE儲存過程。跟蹤其他會話的前提還是需要獲取到會話的SIDSERIAL#,關閉則使用包當中的SESSION_TRACE_DISABLE儲存過程。

儲存過程SESSION_TRACE_ENABLE引數需求如下,詳細可參考官方文件:SESSION_TRACE_ENABLE Procedure

PROCEDURE SESSION_TRACE_ENABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SESSION_ID                     BINARY_INTEGER          IN     DEFAULT    -- 對應SID
 SERIAL_NUM                     BINARY_INTEGER          IN     DEFAULT    -- 對應SERIAL#
 WAITS                          BOOLEAN                 IN     DEFAULT    -- 對應是否加入等待事件跟蹤
 BINDS                          BOOLEAN                 IN     DEFAULT    -- 對應是否加入繫結變數跟蹤
 PLAN_STAT                      VARCHAR2                IN     DEFAULT    -- 對應跟蹤轉儲行資料頻率,取值參考官方文件

儲存過程SESSION_TRACE_DISABLE引數需求如下,詳細可參考官方文件:SESSION_TRACE_DISABLE Procedure

PROCEDURE SESSION_TRACE_DISABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 SESSION_ID                     BINARY_INTEGER          IN     DEFAULT
 SERIAL_NUM                     BINARY_INTEGER          IN     DEFAULT

從以上兩個儲存過程所需引數來看,如果是跟蹤當前會話的話可以省略SESSION_IDSERIAL_NUM這兩個引數,具體的開啟和關閉語句可以參考其他會話跟蹤當中的DBMS_SYSTEM包使用方法。

回到頂部

當前資料庫跟蹤

使用DBMS_MONITOR包還可以用來開啟整個資料庫的跟蹤,但是這會造成trace檔案異常龐大,不便於定位具體問題,而且也會造成一定的效能損失,所以通常不建議開啟。

採用SQL語句方式:

-- 開啟
SYS@dbabd> alter system set sql_trace = true;

-- 關閉
SYS@dbabd> alter system set sql_trace = false;

採用DBMS_MONITOR包方式,主要使用DATABASE_TRACE_ENABLEDATABASE_TRACE_DISABLE兩個儲存過程:

PROCEDURE DATABASE_TRACE_ENABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 WAITS                          BOOLEAN                 IN     DEFAULT
 BINDS                          BOOLEAN                 IN     DEFAULT
 INSTANCE_NAME                  VARCHAR2                IN     DEFAULT
 PLAN_STAT                      VARCHAR2                IN     DEFAULT
PROCEDURE DATABASE_TRACE_DISABLE
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 INSTANCE_NAME                  VARCHAR2                IN     DEFAULT

-- 開啟
SYS@dbabd> exec dbms_monitor.DATABASE_TRACE_ENABLE(true,true,'dbabd','all_executions');

-- 關閉
SYS@dbabd> exec dbms_monitor.DATABASE_TRACE_DISABLE('dbabd');
回到頂部

採用登入觸發器跟蹤

可以通過建立登入觸發器來跟蹤某個使用者的SQL執行效率情況,登入觸發器會在會話初始化的時候去執行,觸發器可以根據指定條件是否對這次會話開啟跟蹤,以下登入觸發器是以SCOTT使用者為例,為SCOTT使用者登入的所有會話設定合適的trace檔案識別符號並開啟跟蹤。

-- 建立觸發器SCOTT_LOGIN_TRACE語句
create or replace trigger scott_login_trace
	after logon on database 
begin
	if user = 'SCOTT'
	then
		execute immediate 'alter session set tracefile_identifier = SCOTT';
		dbms_session.session_trace_enable(waits => true, binds => true, plan_stat => 'all_executions');
	end if;
end;
/

使用SYS使用者進行建立:

SYS@dbabd> create or replace trigger scott_login_trace
  2  after logon on database
  3  begin
  4  if user = 'SCOTT'
  5  then
  6  execute immediate 'alter session set tracefile_identifier = SCOTT';
  7  dbms_session.session_trace_enable(waits => true,
  8                                    binds => true,
  9                                    plan_stat => 'all_executions'
 10  );
 11  end if;
 12  end;
 13  /

Trigger created.

檢視觸發器狀態:

SYS@dbabd> select owner,trigger_name,status,trigger_body from all_triggers where owner = 'SYS' and trigger_name = 'SCOTT_LOGIN_TRACE';

OWNER      TRIGGER_NAME         STATUS     TRIGGER_BODY
---------- -------------------- ---------- --------------------------------------------------------------------------------
SYS        SCOTT_LOGIN_TRACE    ENABLED    begin
                                           if user = 'SCOTT'
                                           then
                                           execute immediate 'alter session set tracefile_identifier = SCOTT';
                                           dbms_session.session_trace_enable(waits => true, binds => true, plan_stat => 'all_executions');
                                           end if;
                                           end;

建立完觸發器之後,SCOTT使用者只要一登入就會預設開啟跟蹤。

回到頂部

總結

以上梳理了常見的開啟SQL TRACE的幾種方式,但是原始的trace檔案可讀性比較差,通常不會直接去讀取,而是通過工具tkprof進行格式化之後進行閱讀,關於tkprof的使用可以參考我另一篇博文:Oracle 11g R2效能優化 tkprof

回到頂部

參考

https://docs.oracle.com/cd/E11882_01/server.112/e41573/sqltrace.htm#PFGRF010
https://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_sessio.htm#ARPLS054
https://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_monitor.htm#ARPLS091

☆〖本人水平有限,文中如有錯誤還請留言批評指正!〗☆