• 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错误。

    有时候需要清理那些长时间处于INACTIVE状态的会话。人为定期检查、杀掉这类会话肯定不太现实,要定期清理那些长时间处于INACTIVE的会话,只能通过作业来实现;另外需要注意,Kill掉这些会话需要需要谨慎,稍不注意,就有可能误杀了一些正常的会话。那么我们该如何定义这类会话呢?下面是我结合业务规则定义的:

      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举例说明。

    clip_image002

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

     如果是RAC环境,那么最好使用下面SQL语句,使用全局视图GV$SESSION。

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

    接下来创建存储过程SYS.DB_KILL_IDLE_CLIENTS. 方便调用该功能执行kill inactive 会话。注意:xxx部分用实际业务的PROGRAM来替代。

    CREATE OR REPLACE PROCEDURE SYS.DB_KILL_IDLE_CLIENTS AUTHID DEFINER AS
       job_no number;
       num_of_kills number := 0;
    BEGIN
    
       FOR REC IN
           (SELECT SID, SERIAL#, INST_ID, MODULE,STATUS
            FROM gv$session S
                WHERE S.USERNAME IS NOT NULL
                AND UPPER(S.PROGRAM) IN('xxx', 'xxx.EXE')
                     AND S.LAST_CALL_ET >= 2*60*60                              
                AND S.STATUS= 'INACTIVE'
            ORDER BY INST_ID ASC
                ) LOOP
    
             ---------------------------------------------------------------------------
    
             -- kill inactive sessions immediately
    
             ---------------------------------------------------------------------------
    
             DBMS_OUTPUT.PUT('LOCAL SID ' || rec.sid || '(' || rec.module || ')');
         execute immediate 'alter system kill session ''' || rec.sid || ', ' ||
                                rec.serial# || '''immediate' ;
             DBMS_OUTPUT.PUT_LINE('. killed locally ' || job_no);
             num_of_kills := num_of_kills + 1;
       END LOOP;
       DBMS_OUTPUT.PUT_LINE ('Number of killed xxxx system sessions: ' || num_of_kills);
    END DB_KILL_IDLE_CLIENTS;
    
    /

    另外,由于kill session是直接将session kill掉,有可能出现导致事物回滚的现象,其实我们可以使用disconnect session完成当前事务并终止session。这种方式比alter system kill session跟安全可靠。

    CREATE OR REPLACE PROCEDURE SYS.DB_KILL_IDLE_CLIENTS AUTHID DEFINER AS
       job_no number;
       num_of_kills number := 0;
    BEGIN
    
       FOR REC IN
           (SELECT SID, SERIAL#, INST_ID, MODULE,STATUS
            FROM gv$session S
                WHERE S.USERNAME IS NOT NULL
                AND UPPER(S.PROGRAM) IN('xxxx', 'xxxx')
                     AND S.LAST_CALL_ET >= 2*60*60                              
                AND S.STATUS<>'KILLED'
            ORDER BY INST_ID ASC
                ) LOOP
             ---------------------------------------------------------------------------
    
             -- kill inactive sessions immediately
    
             ---------------------------------------------------------------------------
    
             DBMS_OUTPUT.PUT('LOCAL SID ' || rec.sid || '(' || rec.module || ')');
             execute immediate 'alter system disconnect session ''' || rec.sid || ', ' ||
                                rec.serial# || '''immediate' ;
              DBMS_OUTPUT.PUT_LINE('. killed locally ' || job_no);
             num_of_kills := num_of_kills + 1;
       END LOOP;
       DBMS_OUTPUT.PUT_LINE ('Number of killed system sessions: ' || num_of_kills);
    END DB_KILL_IDLE_CLIENTS;
    
    /

    然后,我们可以在作业(JOB)或Schedule里面定期调用该存储过程,也可以通过后台作业结合shell脚本实现定期清理空闲会话的功能。例如如下所示。

    创建killSession.sh脚本,调用该存储过程SYS.DB_KILL_IDLE_CLIENTS

    
    
    #!/bin/bash
    
    logfile=/home/oracle/cron/session/log/killSession.log
    
     
    
    echo " " >> $logfile 2>&1
    
    echo "START ----`date`" >> $logfile 2>&1
    
    sqlplus /nolog <<STATS
    
    connect / as sysdba
    
    exec sys.db_kill_idle_clients;
    
    exit;
    
    STATS
    
     
    
    echo "END ------`date`" >> $logfile 2>&1
    
    

    在crontab里面配置后台作业,每隔15分钟运行一次,清理哪些满足条件的空闲会话。

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

  • 相关阅读:
    CSS字体和文本
    【操作系统学习】操作系统概念(一)
    宜家通信 会员管理 表结构搭建
    【优化框架】优化断言,断言返回结果是否包含特定字符串
    【Faker库】faker库(随机生成数据)使用总结转载
    Python+selenium 【第七章】Unittest学习
    Python+selenium 【第六章】UI自动化框架操作测试对象
    Python+selenium 【第五章】UI自动化元素等待
    【Jenkins】python项目集成jenkins并配置allure报告 mac/windows方法一致
    Python+selenium 【第八章】开源项目实战
  • 原文地址:https://www.cnblogs.com/hnsongbiao/p/7446710.html
Copyright © 2020-2023  润新知