在要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 <> 1
4:
5: minus
6:
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