檢視Oracle中儲存過程長時間被卡住的原因
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),此會話的等待事件:
[sql] view plain copy- select * from v$session where sid=***;
event欄位即為等待事件。查詢後我們發現這個會話等待事件為SQL*Net message from dblink;在檢視會話的logon_time為兩天前。這個時間遠超過我們估計時間。
5、根據會話id檢視此會話正在執行的sql語句
[sql]- select sql_text from v$sqlarea where address= (select sql_address from v$session where sid=***);
查詢後發現正在執行的sql語句為通過dblink到遠端資料庫上A表查詢資料,插入到B表。
6、連線遠端資料庫,查詢當前被鎖的物件
[sql]- select * from v$locked_object lo ,
- all_objects ao where lo.OBJECT_ID= ao.object_id ;
檢視後發現遠端資料庫中並沒有涉及到A、B表被鎖
7、檢視遠端資料的會話:
[sql] view plain copy- 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;