oracle數據庫死鎖的查看及解決


Oracle常見死鎖發生的原因以及解決方法

www.MyException.Cn  網友分享於:2014-09-02  瀏覽:0次
 
 
 
Oracle常見死鎖發生的原因以及解決辦法

一,刪除和更新之間引起的死鎖

造成死鎖的原因就是多個線程或進程對同一個資源的爭搶或相互依賴。這里列舉一個對同一個資源的爭搶造成死鎖的實例。

Oracle 10g, PL/SQL version 9.2

CREATE TABLE testLock(  ID NUMBER, 

test VARCHAR(100)  ) 

COMMIT  

 

INSERT INTO testLock VALUES(1,'test1'); 

INSERT INTO testLock VALUES(2,'test2'); 

COMMIT; 

SELECT * FROM testLock 

    

  1.         ID TEST  
  2. ---------- ----------------------------------  
  3.          1 test1  
  4.          2 test2  

 

死鎖現象的重現:

1)在sql 窗口 執行:SELECT * FROM testLock FOR UPDATE; -- 加行級鎖 並對內容進行修改,不要提交

2)另開一個command窗口,執行:delete from testLock WHERE ID=1;

此時發生死鎖(注意此時要另開一個窗口,不然會提示:POST THE CHANGE RECORD TO THE DATABASE. 點yes 后強制commit):

3)死鎖查看:

  1. SQL>  select s.username,l.object_id, l.session_id,s.serial#, s.lockwait,s.status,s.machine,s.program from v$session s,v$locked_object l where s.sid = l.session_id;</p><p>USERNAME    SESSION_ID  SERIAL#    LOCKWAIT STATUS   MACHINE                 PROGRAM  
  2. ----------  ----------  ---------- -------- -------- ----------------------  ------------  
  3. SYS         146         104                 INACTIVE WORKGROUP\J-THINK       PLSQLDev.exe  
  4. SYS         144         145        20834474 ACTIVE   WORKGROUP\J-THINK       PLSQLDev.exe

字段說明:
Username:死鎖語句所用的數據庫用戶;
SID: session identifier, session 標示符,session 是通信雙方從開始通信到通信結束期間的一個上下文。
SERIAL#: sid 會重用,但是同一個sid被重用時,serial#會增加,不會重復。
Lockwait:可以通過這個字段查詢出當前正在等待的鎖的相關信息。
Status:用來判斷session狀態。Active:正執行SQL語句。Inactive:等待操作。Killed:被標注為刪除。
Machine: 死鎖語句所在的機器。
Program: 產生死鎖的語句主要來自哪個應用程序。

4)查看引起死鎖的語句:

SQL>  select sql_text from v$sql where hash_value in   (select sql_hash_value from v$session where sid in  (select session_id from v$locked_object));  

  1.   
  2. SQL_TEXT  
  3. ------------------------------------------------------------  
  1. delete from testLock where  ID = 1  


5)死鎖的處理:

SQL> alter system kill session '144,145';  

  1.   
  2. System altered  
  3.   
  4. Executed in 1.061 seconds  


此時在執行delete語句的窗口出現:

SQL> delete from testLock where  ID = 1;  

  1.   
  2. delete from testLock where  ID = 1  
  3.   
  4. ORA-00028: 您的會話己被終止  


再查看一下死鎖,會發現已經沒有stauts為active的記錄了:

SQL>  select s.username, l.session_id,s.serial#, s.lockwait,s.status,s.machine,s.program from v$session s,v$locked_object l where s.sid = l.session_id;  

  1.   
  2. USERNAME                 SESSION_ID SERIAL#  LOCKWAIT STATUS   MACHINE             PROGRAM  
  3. ------------- ---------- ---------- -------- -------- ---------------------------  ----------------  
  1. SYS                      146        104               INACTIVE WORKGROUP\J-THINK   PLSQLDev.exe  
  2.   
  3. Executed in 0.032 seconds  


發生死鎖的語句已經被終止。

 

二,在外鍵上沒有加索引引起的死鎖

 

客戶的10.2.0.4 RAC for AIX環境頻繁出現ORA-60死鎖問題,導致應用程序無法順利執行。 
經過一系列的診斷,發現最終問題是由於外鍵上沒有建立索引所致,由於程序在主子表上刪除數據,缺少索引導致行級鎖升級為表級鎖,最終導致大量的鎖等待和死鎖。 
下面通過一個例子簡單模擬一下問題: 
SQL> create table t_p (id number primary key, name varchar2(30)); 
Table created. 
SQL> create table t_f (fid number, f_name varchar2(30), foreign key (fid) references t_p); 
Table created. 
SQL> insert into t_p values (1, 'a'); 
1 row created. 
SQL> insert into t_f values (1, 'a'); 
1 row created. 
SQL> insert into t_p values (2, 'b'); 
1 row created. 
SQL> insert into t_f values (2, 'c'); 
1 row created. 
SQL> commit; 
Commit complete. 
SQL> delete t_f where fid = 2; 
1 row deleted. 
這時在會話2同樣對子表進行刪除: 
SQL2> delete t_f where fid = 1; 
1 row deleted. 
回到會話1執行主表的刪除: 
SQL> delete t_p where id = 2; 
會話被鎖,回到會話2執行主表的刪除: 
SQL2> delete t_p where id = 1; 
會話同樣被鎖,這時會話1的語句被回滾,出現ORA-60死鎖錯誤: 
delete t_p where id = 2 

ERROR at line 1: 
ORA-00060: deadlock detected while waiting for resource 
SQL> rollback; 
Rollback complete. 
將會話1操作回滾,會話2同樣回滾並建立外鍵列上的索引: 
1 row deleted. 
SQL2> rollback; 
Rollback complete. 
SQL2> create index ind_t_f_fid on t_f(fid); 
Index created. 
重復上面的步驟會話1刪除子表記錄: 
SQL> delete t_f where fid = 2; 
1 row deleted. 
會話2刪除子表記錄: 
SQL2> delete t_f where fid = 1; 
1 row deleted. 
會話1刪除主表記錄: 
SQL> delete t_p where id = 2; 
1 row deleted. 
會話2刪除主表記錄: 
SQL> delete t_p where id = 1; 
1 row deleted. 
所有的刪除操作都可以成功執行,關於兩種情況下鎖信息的不同這里就不深入分析了,重點就是在外鍵列上建立索引。 
雖然有一些文章提到過,如果滿足某些情況,可以不在外鍵列上建立的索引,但是我的觀點一向是,既然創建了外鍵,就不要在乎再多一個索引,因為一個索引所增加的代價,與缺失這個索引所帶來的問題相比,是微不足道的。


【補充】Oracle 10g和Oracle 9i trc日志內容的差別 
最主要的差別是在Oracle 10g中提示了等待資源的兩條sql語句,在Oracle 9i中,只顯示檢測到死鎖的sql語句 
Oracle 10g 10.2.0.3.0:

DEADLOCK DETECTED ( ORA-00060 )
[Transaction Deadlock]
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TM-0000dd55-00000000        16     146    SX   SSX       17     148    SX   SSX
TM-0000dd55-00000000        17     148    SX   SSX       16     146    SX   SSX
session 146: DID 0001-0010-00000008	session 148: DID 0001-0011-00000006
session 148: DID 0001-0011-00000006	session 146: DID 0001-0010-00000008
Rows waited on:
Session 148: no row
Session 146: no row
Information on the OTHER waiting sessions:
Session 148:
  pid=17 serial=39 audsid=540046 user: 54/SCOTT
  O/S info: user: SKYHOME\sky, term: SKYHOME, ospid: 3028:7000, machine: WORKGROUP\SKYHOME
            program: plsqldev.exe
  application name: PL/SQL Developer, hash value=1190136663
  action name: Command Window - New, hash value=254318129
  Current SQL Statement:
  
delete t_p where id = 1
End of information on OTHER waiting sessions.
Current SQL statement for this session:
delete t_p where id = 2


Oracle 9i 9.2.0.7.0:

DEADLOCK DETECTED
Current SQL statement for this session:
delete t_p where id = 2
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TM-0000260e-00000000        21      51    SX   SSX       23      20    SX   SSX
TM-0000260e-00000000        23      20    SX   SSX       21      51    SX   SSX
session 51: DID 0001-0015-0000043D	session 20: DID 0001-0017-00000397
session 20: DID 0001-0017-00000397	session 51: DID 0001-0015-0000043D
Rows waited on:
Session 20: no row
Session 51: no row
Information on the OTHER waiting sessions:
Session 20:
  pid=23 serial=53179 audsid=197296 user: 87/scott
  O/S info: user: sky, term: SKYHOME, ospid: 5540:4984, machine: WORKGROUP\SKYHOME
            program: plsqldev.exe
  client info: 127.0.0.1
  application name: PL/SQL Developer, hash value=1190136663
  action name: Command Window - New, hash value=254318129
  Current SQL Statement:
  
delete t_p where id = 1
End of information on OTHER waiting sessions.

 

三,兩個表之前不同順序之間的相互更新操作引起的死鎖

 

Oracle中的死鎖: 
 

 
   注:4個update語句的執行順序按圖中位置自上而下 
圖中左邊會話中斷(此時不回滾也不提交,等待用戶決定),右邊會話阻塞,等待左邊會話釋放a表上的鎖。如圖: 
 

 
  
死鎖解決方法: 



  


 修改應用!參考以下方法。 1、將死鎖減至最少 雖然不能完全避免死鎖,但可以使死鎖的數量減至最少。將死鎖減至最少可以增加事務的吞吐量並減少系統開銷,因為只有很少的事務:  
 回滾,而回滾會取消事務執行的所有工作。  由於死鎖時回滾而由應用程序重新提交。  下列方法有助於最大限度地降低死鎖:  
 按同一順序訪問對象。  避免事務中的用戶交互。 
 保持事務簡短並在一個批處理中。  使用低隔離級別。  使用綁定連接。  2、按同一順序訪問對象 
如果所有並發事務按同一順序訪問對象,則發生死鎖的可能性會降低。例如,如果兩個並發事務獲得 Supplier 表上的鎖,然后獲得 Part 表上的鎖,則在其中一個事務完成之前,另一個事務被阻塞在 Supplier 表上。第一個事務提交或回滾后,第二個事務繼續進行。不發生死鎖。將存儲過程用於所有的數據修改可以標准化訪問對象的順序。 
 

 
3、避免事務中的用戶交互 避免編寫包含用戶交互的事務,因為運行沒有用戶交互的批處理的速度要遠遠快於用戶手動響應查詢的速度,例如答復應用程序請求參數的提示。例如,如果事務正在等待用戶輸入,而用戶去吃午餐了或者甚至回家過周末了,則用戶將此事務掛起使之不能完成。這樣將降低系統的吞吐量,因為事務持有的任何鎖只有在事務提交或回滾時才會釋放。即使不出現死鎖的情況,訪問同一資源的其它事務也會被阻塞,等待該事務完成。 4、保持事務簡短並在一個批處理中 
在同一數據庫中並發執行多個需要長時間運行的事務時通常發生死鎖。事務運行時間越長,其持有排它鎖或更新鎖的時間也就越長,從而堵塞了其它活動並可能導致死鎖。 保持事務在一個批處理中,可以最小化事務的網絡通信往返量,減少完成事務可能的延遲並釋放鎖。


免責聲明!

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



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