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