日期:2014-05-16  浏览次数:20420 次

Oracle-解除死锁方法

当利用PL/SQL执行一个sql语句的时候,有时候中途手动终止了该语句的执行,但是利用


--查看正在运行的sql语句

select a.*,s.*
? from v$sqltext a,v$session s
?where s.STATUS ='ACTIVE' and s.SQL_HASH_VALUE =a.hash_value
?order by s.USERNAME,a.PIECE


会发现,该语句还在运行,这时候就要终止sql语句锁对应的session,方法如下:

1. 利用“查看正在运行的sql语句”找到该sql语句对应的sid 和 serial#

2. 执行alter system kill session 'sid,serial#' ,终止该session

3. 执行
select saddr,sid,serial#,paddr,username,status from v$session where username is not null
查看session是否被成功终止,我们会发现被kill掉的session,状态会被标记为killed,同时该session对应的paddr被修改,如果有多个session被kill,那么多个被kill的session的paddr都被更改为相同的进程地址。
但其实这种情况下,很多时候,session占用的资源是无法释放的,我们需要查询spid,在操作系统级来kill这些进程。我们可以通过如下语句查看系统中被锁的对象:
select lpad(' ', decode(l.xidusn, 0, 3, 0)) || l.oracle_username user_name,
??? o.owner, o.object_name, o.object_type, s.sid, s.serial#, p.spid
??? from v$locked_object l, dba_objects o, v$session s, v$process p
??? where l.object_id = o.object_id and l.session_id = s.sid and s.paddr = p.addr
??? order by o.object_id, xidusn desc

4. 但是由于被kill的session的paddr已经改变,我们无法通过v$session和v$process关联来获得该session对应os的进程。通过执行如下语句,来找到status=killed的session的addr,即为被Kill掉的session的进程地址。
SELECT s.username,s.status,
??? x.ADDR,x.KSLLAPSC,x.KSLLAPSN,x.KSLLASPO,x.KSLLID1R,x.KSLLRTYP,
?? decode(bitand (x.ksuprflg,2),0,null,1)
?? FROM x$ksupr x,v$session s
??? WHERE s.paddr(+)=x.addr
?? and bitand(ksspaflg,1)!=0


5. 现在我们获得了session的地址,就可以在v$process中找到spid,select * from v$process v where v.addr='*******'

6. 登录操作系统,利用kill -9杀死对应的进程。

?

??? 实际上,当在Oracle中kill session以后, Oracle只是简单的把相关session的paddr 指向同一个虚拟地址.此时v$process和v$session失去关联,进程就此中断.
然后Oracle就等待PMON(Oracle的后台进程之一,用来清理失败的进程)去清除这些Session.所以通常等待一个被标记为Killed的Session退出需要花费很长的时间.


??? 注意:数据库相关查询需要 DBA 权限~