我们知道,在Oracle数据库中,可以通过kill session的方式来终止一个进程,其基本语法结构为:
alter system kill session 'sid,serial#' ;
被kill掉的session,状态会被标记为killed,Oracle会在该用户下一次toUCh时清除该进程.
我们发现当一个session被kill掉以后,该session的paddr被修改,假如有多个session被kill,那么多个session的paddr都被更改为相同的进程地址:
SQL select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SIDSERIAL# PADDRUSERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11314 542B70E8 EYGLEINACTIVE
542E5044 18662 542B6D38 SYSACTIVE
SQL alter system kill session '11,314';
System altered.
SQL select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SIDSERIAL# PADDRUSERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11314 542D6BD4 EYGLEKILLED
542E5044 18662 542B6D38 SYSACTIVE
SQL select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SIDSERIAL# PADDRUSERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11314 542D6BD4 EYGLEKILLED
542E2AA4 14397 542B7498 EQSP INACTIVE
542E5044 18662 542B6D38 SYSACTIVE
SQL alter system kill session '14,397';
System altered.
SQL select saddr,sid,serial#,paddr,username,status from v$session where username is not null;
SADDR SIDSERIAL# PADDRUSERNAME STATUS
-------- ---------- ---------- -------- ------------------------------ --------
542E0E6C 11314 542D6BD4 EYGLEKILLED
542E2AA4 14397 542D6BD4 EQSP KILLED
542E5044 18662 542B6D38 SYSACTIVE
在这种情况下,很多时候,资源是无法释放的,我们需要查询spid,在操作系统级来kill这些进程.
但是由于此时v$session.paddr已经改变,我们无法通过v$session和v$process关联来获得spid
那还可以怎么办呢?
我们来看一下下面的查询:
SQL SELECT s.username,s.status,
2x.ADDR,x.KSLLAPSC,x.KSLLAPSN,x.KSLLASPO,x.KSLLID1R,x.KSLLRTYP,
3decode(bitand (x.ksuprflg,2),0,null,1)
4FROM x$ksupr x,v$session s
5WHERE s.paddr(+)=x.addr
6and bitand(ksspaflg,1)!
=0;
USERNAME STATUS ADDR KSLLAPSC KSLLAPSN KSLLASPO KSLLID1R KS D
------------------------------ -------- -------- ---------- ---------- ------------ ---------- -- -
542B44A800 0
ACTIVE 542B48581 14 24069 01
ACTIVE 542B4C08 26 16 15901 01
ACTIVE 542B4FB87 46 24083 01
ACTIVE 542B5368 12 15 24081 01
ACTIVE 542B5718 15 46 24083 01
ACTIVE 542B5AC8 794 15923 01
ACTIVE 542B5E78 50 16 24085 01
ACTIVE 542B6228754 15 24081 01
ACTIVE 542B65D81 14 24069 01
ACTIVE 542B69882 30 14571 01
USERNAME STATUS ADDR KSLLAPSC KSLLAPSN KSLLASPO KSLLID1R KS D
------------------------------ -------- -------- ---------- ---------- ------------ ---------- -- -
SYSACTIVE 542B6D3828 24071 0
542B70E81 15 24081 195 EV
542B74981 15 24081 195 EV
SYSINACTIVE 542B784800 0
SYSINACTIVE 542B7BF81 15 24081 195 EV
16 rows selected.
简化一点,其实就是如下概念:
SQL select p.addr from v$process p where pid < 1 2 minus 3 select s.paddr from v$session s;
ADDR
--------
542B70E8
542B7498
现在我们获得了进程地址,就可以在v$process中找到spid,然后可以使用Kill或者orakill在系统级来杀掉这些进程.
当在Oracle中kill session以后, Oracle只是简单的把相关session的paddr 指向同一个虚拟地址.
此时v$process和v$session失去关联,进程就此中断.
然后Oracle就等待PMON去清除这些Session.所以通常等待一个被标记为Killed的Session退出需要花费很长的时间.
假如此时被Kill的process,重新尝试执行任务,那么马上会收到进程中断的提示,process退出,此时Oracle会立即启动PMON来清除该session.这被作为一次异常中断处理.