ORACLE按期清理INACTIVE會話

  ORACLE數據庫會話有ACTIVE、INACTIVE、KILLED、 CACHED、SNIPED五種狀態。INACTIVE狀態的會話表示此會話處於非活動、空閒、等待狀態。例如PL/SQL Developer鏈接到數據庫,執行一條SQL語句後,若是不繼續執行SQL語句,那麼此會話就處於INACTIVE狀態。通常狀況下,少許的INACTVIE會話對數據庫並無什麼影響,若是因爲程序設計等某些緣由致使數據庫出現大量的會話長時間處於INACTIVE狀態,那麼將會致使大量的系統資源被消耗,形成會話數超過系統session的最大值,出現ORA-00018:maximum number of sessions exceeded錯誤。sql

有時候須要清理那些長時間處於INACTIVE狀態的會話。人爲按期檢查、殺掉這類會話確定不太現實,要按期清理那些長時間處於INACTIVE的會話,只能經過做業來實現;另外須要注意,Kill掉這些會話須要須要謹慎,稍不注意,就有可能誤殺了一些正常的會話。那麼咱們該如何定義這類會話呢?下面是我結合業務規則定義的:shell

  1: 會話的Status必須爲INACTIVE,若是會話狀態爲ACTIVE、KILLED、CACHED、SNIPED狀態,不作考慮。數據庫

  2: 會話必須已經長時間處於INACTIVE狀態。例如,處於INACTIVE狀態超過了兩小時的會話進程,才考慮Kill。這個視具體業務或需求決定,有可能超過半小時就能夠殺掉會話進程。至於如何計算處於INACTIVE會話狀態的時間,這個能夠 經過V$SESSION的LAST_CALL_ET字段來判別,須要查詢處於INACTIVE狀態兩小時或以上的會話,就能夠經過查詢條件S.LAST_CALL_ET >= 60*60*2實現,固然最好寫成 S.LAST_CALL_ET >= 7200安全

  3: 鏈接到會話的程序。好比,某個特定的應用程序產生的INACTIVE會話纔要清理。例如, Toad工具、PL/SQL Developer工具。關於PROGRAM這個須要根據當前項目的具體狀況設置,下面僅僅使用TOAD.EXE、W3WP.EXE舉例說明。bash

clip_image002

   1: SELECT SID, SERIAL#,MODULE, STATUS
   2: FROM V$SESSION S
   3: WHERE S.USERNAME IS NOT NULL
   4: AND UPPER(S.PROGRAM) IN ('TOAD.EXE', 'W3WP.EXE')
   5: AND S.LAST_CALL_ET >= 60*60*2
   6: AND S.STATUS = 'INACTIVE'
   7: ORDER BY SID DESC;

若是是RAC環境,那麼最好使用下面SQL語句,使用全局視圖GV$SESSION。session

   1: SELECT SID, SERIAL#, INST_ID, MODULE,STATUS
   2: FROM gv$session S
   3: WHERE S.USERNAME IS NOT NULL
   4: AND UPPER(S.PROGRAM) IN ('TOAD.EXE', 'W3WP.EXE')
   5: AND S.LAST_CALL_ET >= 2 * 60*60
   6: AND S.STATUS = 'INACTIVE'
   7: ORDER BY INST_ID DESC

接下來建立存儲過程SYS.DB_KILL_IDLE_CLIENTS. 方便調用該功能執行kill inactive 會話。注意:xxx部分用實際業務的PROGRAM來替代。oracle

   1:  
   2: CREATE OR REPLACE PROCEDURE SYS.DB_KILL_IDLE_CLIENTS AUTHID DEFINER AS
   3:    job_no number;
   4:    num_of_kills number := 0;
   5: BEGIN
   6:  
   7:    FOR REC IN
   8:        (SELECT SID, SERIAL#, INST_ID, MODULE,STATUS
   9:         FROM gv$session S
  10:             WHERE S.USERNAME IS NOT NULL
  11:             AND UPPER(S.PROGRAM) IN ('xxx', 'xxx.EXE')   
  12:                  AND S.LAST_CALL_ET >= 2*60*60                              
  13:             AND S.STATUS= 'INACTIVE'
  14:         ORDER BY INST_ID ASC
  15:             ) LOOP
  16:          ---------------------------------------------------------------------------
  17:          -- kill inactive sessions immediately
  18:          ---------------------------------------------------------------------------
  19:          DBMS_OUTPUT.PUT('LOCAL SID ' || rec.sid || '(' || rec.module || ')');
  20:      execute immediate 'alter system kill session ''' || rec.sid || ', ' ||
  21:                             rec.serial# || '''immediate' ;
  22:      
  23:          DBMS_OUTPUT.PUT_LINE('. killed locally ' || job_no);
  24:          num_of_kills := num_of_kills + 1;
  25:    END LOOP;
  26:    DBMS_OUTPUT.PUT_LINE ('Number of killed xxxx system sessions: ' || num_of_kills);
  27: END DB_KILL_IDLE_CLIENTS;
  28: /

另外,因爲kill session是直接將session kill掉,有可能出現致使事物回滾的現象,其實咱們可使用disconnect session完成當前事務並終止session。這種方式比alter system kill session跟安全可靠。app

   1: CREATE OR REPLACE PROCEDURE SYS.DB_KILL_IDLE_CLIENTS AUTHID DEFINER AS
   2:    job_no number;
   3:    num_of_kills number := 0;
   4: BEGIN
   5:  
   6:    FOR REC IN
   7:        (SELECT SID, SERIAL#, INST_ID, MODULE,STATUS
   8:         FROM gv$session S
   9:             WHERE S.USERNAME IS NOT NULL
  10:             AND UPPER(S.PROGRAM) IN ('xxxx', 'xxxx')   
  11:                  AND S.LAST_CALL_ET >= 2*60*60                              
  12:             AND S.STATUS<>'KILLED'
  13:         ORDER BY INST_ID ASC
  14:             ) LOOP
  15:          ---------------------------------------------------------------------------
  16:          -- kill inactive sessions immediately
  17:          ---------------------------------------------------------------------------
  18:          DBMS_OUTPUT.PUT('LOCAL SID ' || rec.sid || '(' || rec.module || ')');
  19:          execute immediate 'alter system disconnect session ''' || rec.sid || ', ' ||
  20:                             rec.serial# || '''immediate' ;
  21:  
  22:          DBMS_OUTPUT.PUT_LINE('. killed locally ' || job_no);
  23:          num_of_kills := num_of_kills + 1;
  24:    END LOOP;
  25:    DBMS_OUTPUT.PUT_LINE ('Number of killed system sessions: ' || num_of_kills);
  26: END DB_KILL_IDLE_CLIENTS;
  27: /

而後,咱們能夠在做業(JOB)或Schedule裏面按期調用該存儲過程,也能夠經過後臺做業結合shell腳本實現按期清理空閒會話的功能。例如以下所示。工具

建立killSession.sh腳本,調用該存儲過程SYS.DB_KILL_IDLE_CLIENTSspa

   1: #!/bin/bash
   2:  
   3:  
   4:  
   5: logfile=/home/oracle/cron/session/log/killSession.log
   6:  
   7: echo " " >> $logfile 2>&1
   8: echo "START ----`date`" >> $logfile 2>&1
   9: sqlplus /nolog <<STATS
  10: connect / as sysdba
  11: exec sys.db_kill_idle_clients;
  12: exit;
  13: STATS
  14:  
  15: echo "END ------`date`" >> $logfile 2>&1

在crontab裏面配置後臺做業,每隔15分鐘運行一次,清理哪些知足條件的空閒會話。

0,15,30,45 * * * * /home/oracle/cron/session/bin/killSession.sh >/dev/null 2>&1

相關文章
相關標籤/搜索