一、为什么要kill session
很多的时候我们迅速的杀掉Oralcle的一些session,理由大体如下:

1、  一些时候,由于我们的数据量很大,相应的事务大并且多,在做shutdown immediate的时候会花费好多的时间,而我们却想用shutdown immediate的方式,而又要把数据库迅速的shutdown下来。

2、  我们的应用可能使用了会话控制,即在应用的层面控制了一些用户的连接的数量。但有时可能网络发生的瞬断,从而就产生了一些死进程,他们的状态为Inactive的状态。当我们用alter system kill session ‘sid,serial#’进行清除时,这些session的状态又变成了killed,这些就由Pmon进程来慢慢进行清除了,而你恰恰又是个急脾气。

3、  系统忽然慢了现来,你发现是某个session在做怪,想迅速把它迅速结束掉。

二、如何kill session
锁的产生,config:

(1)环境:PL/SQL developer:
SQL> create table Spread(id number(6),
  2  mobile char(11)
  3  );
 
Table created
 
SQL> insert into spread(id,mobile)
  2  values(1,'13515127139');
 
1 row inserted

(2)环境:Rapid SQL
insert into spread(id,mobile)
values(3,'1583676639')
/
insert into spread(id,mobile)
values(2,'1583676739')
/
update spread
set mobile='11111111111'
where id=1

以上DML均未commit;

(3)然后:
truncate table spread

接着报错:
ORA-00054: resource busy and acquire with NOWAIT specified

那么,怎么解决这个问题呢?
首先找出这个表是不是被锁住?
select b.owner table_owner,b.object_name,c.username,c.sid,c.serial#,c.PADDR
from v$locked_object a,dba_objects b,v$session c
where a.object_id=b.object_id and c.sid=a.session_id;
----------------
TABLE_OWNER OBJECT_NAME USERNAME SID SERIAL# PADDR
EDU SPREAD EDU 219 8244 0000000072B71878
EDU SPREAD EDU 178 10231 0000000072B75FA0

锁住的原因:
SELECT lk.SID, se.username, se.osuser, se.machine,se.sid,se.serial#,se.PADDR,
       DECODE (lk.TYPE,
               'TX', 'Transaction',
               'TM', 'DML',
               'UL', 'PL/SQL User Lock',
               lk.TYPE
              ) lock_type,
       DECODE (lk.lmode,
               0, 'None',
               1, 'Null',
               2, 'Row-S (SS)',
               3, 'Row-X (SX)',
               4, 'Share',
               5, 'S/Row-X (SSX)',
               6, 'Exclusive',
           TO_CHAR (lk.lmode)
              ) mode_held,
       DECODE (lk.request,
               0, 'None',
               1, 'Null',
               2, 'Row-S (SS)',
               3, 'Row-X (SX)',
               4, 'Share',
               5, 'S/Row-X (SSX)',
               6, 'Exclusive',
               TO_CHAR (lk.request)
              ) mode_requested,
       TO_CHAR (lk.id1) lock_id1, TO_CHAR (lk.id2) lock_id2, ob.owner,
       ob.object_type, ob.object_name, lk.BLOCK, se.lockwait
  FROM v$lock lk, dba_objects ob, v$session se
 WHERE lk.TYPE IN ('TM', 'UL') AND lk.SID = se.SID AND lk.id1 = ob.object_id(+)
----------------------
SID USERNAME OSUSER MACHINE SID SERIAL# PADDR LOCK_TYPE MODE_HELD MODE_REQUESTED LOCK_ID1 LOCK_ID2 OWNER OBJECT_TYPE OBJECT_NAME BLOCK LOCKWAIT
178 EDU jhj EDU\JIANGHUANJUN 178 10231 0000000072B75FA0 DML Row-X (SX) None 123257 0 EDU TABLE SPREAD 0 [NULL]
219 EDU jhj EDU\JIANGHUANJUN 219 8244 0000000072B71878 DML Row-X (SX) None 123257 0 EDU TABLE SPREAD 0 [NULL]

/


根据在Oracle数据库中,可以通过kill session的方式来终止一个进程,其基本语法结构为:
alter system kill session 'sid,serial#' ; 
然后
alter system kill session '219,8244';
 System altered
 
然后
select b.owner table_owner,b.object_name,c.username,c.sid,c.serial#,c.PADDR
from v$locked_object a,dba_objects b,v$session c
where a.object_id=b.object_id and c.sid=a.session_id;
显示为null
而且再次提交原来的对话框 会提示 your session has been killed;
 
 
查看此时的session"
select saddr,sid,serial#,paddr,username,status 
from v$session 
where username='EDU'
------------------------------------
SADDR SID SERIAL# PADDR USERNAME STATUS
000000007208DA58 86 6469 0000000072B77758 EDU INACTIVE
0000000072090528 88 9550 0000000072B77F40 EDU INACTIVE
00000000720A9BE0 107 7623 0000000072B76F70 EDU INACTIVE
00000000720C1D30 125 28979 0000000072B73030 EDU INACTIVE
00000000720E49C0 151 12337 0000000072B796F8 EDU ACTIVE
0000000072128D78 202 13727 0000000072B76788 EDU INACTIVE
   000000007213F960 219 8244 0000000072BDEA58 EDU KILLED   可以看到Killed
000000007214A4A0 227 16252 0000000072B78728 EDU INACTIVE
000000007216E698 254 11533 0000000072B747E8 EDU INACTIVE

再kill一个session
alter system kill session '86,6469' 
 
查看此时的session对应的process
select saddr,sid,serial#,paddr,username,status 
from v$session 
where username='EDU'
order by paddr
---------------------------------
SADDR                   SID    SERIAL# PADDR            USERNAME                       STATUS
---------------- ---------- ---------- ---------------- ------------------------------ --------
00000000720C1D30        125      28979 0000000072B73030 EDU                            INACTIVE
000000007216E698        254      11533 0000000072B747E8 EDU                            INACTIVE
0000000072128D78        202      13727 0000000072B76788 EDU                            INACTIVE
00000000720A9BE0        107       7623 0000000072B76F70 EDU                            INACTIVE
0000000072090528         88       9550 0000000072B77F40 EDU                            INACTIVE
000000007214A4A0        227      16252 0000000072B78728 EDU                            INACTIVE
00000000720E49C0        151      12337 0000000072B796F8 EDU                            INACTIVE
 000000007208DA58         86       6469 0000000072BDEA58 EDU                            KILLED
 000000007213F960        219       8244 0000000072BDEA58 EDU                            KILLED
 被kill的两个session此时的process PADDR一致;
 
这是什么原因嘞?
在这种情况下,很多时候,资源是无法释放的,我们需要查询spid,在操作系统级来kill这些进程.
但是由于此时v$session.paddr已经改变,我们无法通过v$session和v$process关联来获得spid
那还可以怎么办呢?

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
  order By x.ADDR,x.KSLLAPSC,x.KSLLAPSN,x.KSLLASPO
/
select p.addr from v$process p where pid <> 1
 minus
select s.paddr from v$session s;

找到是被Kill掉的进程的进程地址.
ADDR
----------------
0000000072B68240
0000000072B68A28
0000000072B71878
0000000072B77758

then,现在我们获得了进程地址,就可以在v$process中找到spid,然后可以使用Kill或者orakill在系统级来杀掉这些进程.
select *
from v$process  p
where p.ADDR
IN(
 '0000000072B68240',
'0000000072B68A28',
'0000000072B71878',
'0000000072B77758'
)
------------------------
SPID
24375
24377
12385
10283
-----------
orakill sid spid

c:\>orakill 219,24375;

posted on 2010-07-15 23:32  维也纳下午茶  阅读(723)  评论(0编辑  收藏  举报