查看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
  1. select * from v$session where sid=***;  

event字段即為等待事件。查詢后我們發現這個會話等待事件為SQL*Net message from dblink;在查看會話的logon_time為兩天前。這個時間遠超過我們估計時間。

5、根據會話id查看此會話正在執行的sql語句

[sql]  view plain copy
  1. select sql_text from v$sqlarea where address= (select   sql_address  from v$session where sid=***);  

查詢后發現正在執行的sql語句為通過dblink到遠程數據庫上A表查詢數據,插入到B表。

6、連接遠程數據庫,查詢當前被鎖的對象

[sql]  view plain copy
  1. select * from v$locked_object lo ,   
  2. all_objects  ao    where lo.OBJECT_ID= ao.object_id ;  

查看后發現遠程數據庫中並沒有涉及到A、B表被鎖

7、查看遠程數據的會話:

[sql]  view plain copy
  1. 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;



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM