1:查V$DB_OBJECT_CACHE
SELECT * FROM V$DB_OBJECT_CACHE WHERE name='CUX_OE_ORDER_RPT_PKG' AND LOCKS!='0';
注意:CUX_OE_ORDER_RPT_PKG 為存儲過程的名稱。
發現 locks=2
2:按對象查出sid的值
select /*+ rule*/ SID from V$ACCESS WHERE object='CUX_OE_ORDER_RPT_PKG';
注意:CUX_OE_ORDER_RPT_PKG 為存儲過程的名稱。
3:查sid,serial#
SELECT SID,SERIAL#,PADDR FROM V$SESSION WHERE SID='剛才查到的SID';
4、根據會話id(sid),此會話的等待事件:
- select * from v$session where sid=***;
event字段即為等待事件。查詢后我們發現這個會話等待事件為SQL*Net message from dblink;在查看會話的logon_time為兩天前。這個時間遠超過我們估計時間。
5、根據會話id查看此會話正在執行的sql語句
- select sql_text from v$sqlarea where address= (select sql_address from v$session where sid=***);
查詢后發現正在執行的sql語句為通過dblink到遠程數據庫上A表查詢數據,插入到B表。
6、連接遠程數據庫,查詢當前被鎖的對象
- select * from v$locked_object lo ,
- all_objects ao where lo.OBJECT_ID= ao.object_id ;
查看后發現遠程數據庫中並沒有涉及到A、B表被鎖
7、查看遠程數據的會話:
- select * from v$session where terminal like '%機器名%' and program='Oracle.exe'
使用dblink連接遠程數據庫,在遠程數據庫上的會話的program應該是是oracle.exe
查詢后發現,兩個遠程庫有時候根本沒有相關會話,有時候可能有相關會話,但其等待事件是 SQL*Net message from client 遠程庫在等待本地Oracle給他發請求。
本地庫等dblink遠程庫,遠程庫等待client消息。看來這個存儲過程是不可能執行完了。
具體什么原因造成了,還不清楚。
這里給出的處理方法就是殺死會話
http://blog.csdn.net/fupei/article/details/7325190
具體步驟可參考上面的文章
一些項目中使用了job定期執行sql語句。如果要執行的sql語句是基於dblink對遠程數據庫的訪問,那么有時候就會出現該sql語句長時間執行一直不結束的情況。並且這時在遠程數據庫上並沒有鎖導致該sql語句等待(這可能是由於網絡問題觸發的oracle的一個bug吧,遠程數據庫與本地數據之間有防火牆時比較容易出現這個現象)。
下面總結了如何判斷該job是否長時間執行沒結束,並說明了處理步驟。
1)、觀察job情況。
system用戶下執行語句select * from dba_jobs;找到有問題的job,記錄下該job在查詢結果中job列的取值,該取值稱為job號。
broken字段為N,且this_date字段的時間比當前時間減去執行周期要晚(根據interval字段判斷),則job是正常的。如果this_date字段沒有值,一般認為job當前沒有在執行。
如果broken字段N,並且this_date時間不對(例如是幾個小時以前,甚至幾天以前),則說明該job某一次周期一直沒有執行完。
如果出現這種現象,就說明該job可能出問題了。
2)、查找該job目前正在執行時的會話編號sid
select * from dba_jobs_running where job='剛才查到的job號';
在返回結果中記錄sid列的取值
3)、查看該會話
select * from v$session where sid='剛才查到的sid'
記錄下返回結果的 serial#列(會話序列號),paddr列(線程地址)
4)、 取得會話的線程號
select spid from v$process where addr='剛才查到的線程地址' ;
記錄下列spid,稱為線程號
5)、使用oracle命令殺會話
alter system kill session '會話編號sid,會話序列號serial#';
6)、查看是否成功殺掉該會話(方法與步驟一相同,多執行幾次select * from dba_jobs;觀察結果)
7)、如果沒有殺掉會話,就是用操作系統命令殺線程(或進程)
這里給出windows下殺oracle會話占用的線程的方法
登錄到數據庫所在的操作系統中,打開windows命令行,鍵入命令: orakill 數據庫sid 剛才查到的線程號spid
例如 orakill orcl 12345
這里給出一個自動清理問題job的存儲過程,由於是存儲過程,只能使用alter system kill 來殺會話,有時候會話只被標記為killed,並不能真正結束,job也無法啟動下一個周期。
CREATE OR REPLACE PROCEDURE SYS.PRO_KILL_JOB AS
/*清理job567 568 569 長期執行不結束的情況*/
/*30分鍾超時*/
CURSOR MYCUR IS
select ' ALTER SYSTEM KILL SESSION '''||s.sid ||','|| s.SERIAL#||''' immediate ' AS SQL_KILL , J.JOB
from dba_jobs_running j,v$session s
where j.sid=s.sid and
this_date <(sysdate-30/24/60) and
s.sid is not null and s.serial# is not null
and
( j.job= 567
or j.job=568
or j.job=569 ) ;
V_SQL_KILL VARCHAR2(500);
V_JOB NUMBER ;
BEGIN
OPEN MYCUR;
LOOP
FETCH MYCUR
INTO V_SQL_KILL , V_JOB;
EXIT WHEN MYCUR%NOTFOUND;
dbms_output.put_line(v_sql_kill);
execute immediate v_sql_kill ;
COMMUNICATION.SP_DB_LOG('PRO_KILL_JOB', 1, NULL, V_JOB||' IS KILLED');
COMMIT;
END LOOP;
CLOSE MYCUR;
EXCEPTION
WHEN OTHERS THEN
COMMUNICATION.SP_DB_LOG('PRO_KILL_JOB', 1, SQLCODE, SQLERRM);
COMMIT;
END PRO_KILL_JOB;