在要drop一个数据库用户时发现这个用户已连接到数据库,因此没法直接drop掉这个用户。使用
1: select * from v$session where username='USERNAME' and STATUS <>'KILLED'
查看出要kill掉的session后,发现有近15个session。发现这样一个个去kill,太慢了,就来了招狠的:
1: SELECT CONCAT('ALTER SYSTEM KILL SESSION ''',CONCAT(CONCAT(CONCAT(SID,','),SERIAL#),''';')) FROM V$SESSION WHERE USERNAME='SCOTT'
最后生成了一堆类似:
1: ALTER SYSTEM KILL SESSION 'SID,SERIAL';
这样的语句。
将这一堆语句贴到dbvis中,执行了下,确实是把所有与USERNMAE相关的sessionkill掉了,但是下次用USERNAME用户登录后,发现session个数并没有掉下去。
从网上查资料来看,“当一个session被kill掉以后,该session的paddr被修改,如果有多个 session被kill,那么多个session的paddr都被更改为相同的进程地址”,在这种情况下,先前被占用的资源是无法被释放的,因此要从操作系统级去释放这些资源。实际上,在数据库层,每生成一个session,在Solaris上会新增一个oracle用户的进程,windows上由于有线程机制,会在oracle.exe中生成对应的线程。
因此,在Solaris下,确定好了要清除的session对应的操作系统级别的进程,然后在把这些进程kill掉,下次进入系统,就可以看到先前被占用的session在V$SESSION中找不到了。
那么,怎么去判断要被清除掉的session对应的操作系统进程呢?网上有位前辈说“当在Oracle中kill session以后, Oracle只是简单的把相关session的paddr 指向同一个虚拟地址.此时v$process和v$session失去关联,进程就此中断.然后Oracle就等待PMON去清除这些Session.所以通常等待一个被标记为Killed的 Session退出需要花费很长的时间.”
根据那位牛人的文章,我自己写了个sql:
1: SELECT CONCAT('kill -9 ',SPID) FROM V$PROCESS WHERE V$PROCESS.ADDR IN(2:3: select p.addr from v$process p where pid <> 14:5: minus6:7: select s.paddr from v$session s)
在dbvis中执行,执行的结果是生成一堆(又是一堆,-_-!)kill –9 pid这样的语句,将执行结果贴到securecrt中(此时securecrt以oracle用户连接到了对应的Solaris机器上),执行完成后,再用先前的USERNAME这个用户登录数据库,TOUCH一下,退出后,就可以用dba用户drop掉USERNAME用户了。
补充:最后上网找了半天,终于把那位牛人前辈的文章位置找到了:http://www.eygle.com/archives/2004/06/kill_session.html