解決Oracle資料庫死鎖
介紹
本文我們嘗試總結在多個使用者併發情況下,如何識別和解決刪除操作期間發生的死鎖問題,在開始之前,我們先簡單描述一下什麼是死鎖以及什麼東西會導致死鎖。
死鎖
在任何資料庫中發生死鎖都是不愉快的,即使是在一個特殊的情況下發生也是如此,它們會減小應用程式的接受程度(ACCEPTANCE),因此避免並正確解釋死鎖是非常重要的。
當兩個或更多使用者相互等待鎖定的資料時就會發生死鎖,發生死鎖時,這些使用者被卡住不能繼續處理業務,Oracle自動檢測死鎖並解決它們(透過回滾一個包含在死鎖中的語句實現),釋放掉該語句鎖住的資料,回滾的會話將會遇到Oracle錯誤“ORA-00060:等待資源時檢測到死鎖”。
是什麼導致了死鎖?
明確地鎖定表是為了保證讀/寫一致性,未建立索引的外來鍵約束,在相同順序下表不會鎖住,沒有為資料段分配足夠的 儲存引數(主要是指INITTRANS,MAXTRANS和PCTFREE引數)很容易引發突發鎖和死鎖,原因是多種多樣的,需要重新逐步審查。
識別死鎖
當Oracle資料庫檢測到死鎖時(Oracle錯誤訊息:ORA-00060),相應的訊息就寫入到警告日誌檔案中(alert.log),另外還會在USER_DUMP_DEST目錄下建立一個跟蹤檔案,分析警告日誌檔案和跟蹤檔案是非常耗時的。
下面是一個警告日誌檔案示例:
Mon Aug 07 09:14:42 2007
ORA-000060: Deadlock detected. More info in file
e:\oracle\admin\GEDEON\udump\ORA01784.TRC.
下面是從跟蹤檔案中節選出來的片段,從其中我們可以看出是哪個語句創造了死鎖,相關的語句和被鎖定的資源已經標記為粗體。
/users/ora00/log/odn_ora_1097872.trc
Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production
ORACLE_HOME = /soft/ora920
System name:AIX
Node name:beaid8
Release:2
Version:5
Machine:00C95B0E4C00
Instance name: ODN
Redo thread mounted by this instance: 1
Oracle process number: 17
Unix process pid: 1097872, image: oracle@beaid8 (TNS V1-V3)
*** 2007-06-04 14:41:04.080
*** SESSION ID:(10.6351) 2007-06-04 14:41:04.079
DEADLOCK DETECTED ( ORA-00060 )
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-00001720-00000000 17 10 SX 16 18 SX SSX
TM-0000173a-00000000 16 18 SX 17 10 SX SSX
session 10: DID 0001-0011-00000002session 18: DID 0001-0010-00000022
session 18: DID 0001-0010-00000022session 10: DID 0001-0011-00000002
Rows waited on:
Session 18: obj - rowid = 00001727 - AAABcnAAJAAAAAAAAA
(dictionary objn - 5927, file - 9, block - 0, slot - 0)
Session 10: obj - rowid = 00001727 - AAABcnAAJAAAAAAAAA
(dictionary objn - 5927, file - 9, block - 0, slot - 0)
Information on the OTHER waiting sessions:
Session 18:
pid=16 serial=2370 audsid=18387 user: 21/ODN
O/S info: user: mwpodn00, term: unknown, ospid: , machine: beaida
program: JDBC Thin Client
application name: JDBC Thin Client, hash value=0
Current SQL Statement:
DELETE FROM ODNQTEX WHERE EX_ID = :B1
End of information on OTHER waiting sessions.
Current SQL statement for this session:
DELETE FROM ODNQTFN WHERE FN_ID_EXIGENCE_EX = :B1
----- PL/SQL Call Stack -----
object line object
handle number name
7000000135f7fd8 34 procedure ODN.ODNQPDR
7000000135f89f0 16 procedure ODN.ODNQPZB
我們可以使用企業管理器來決定保留所有的鎖還是釋放掉它們,為了便於說明,我們開啟2個sqlplus例項會話(在此期間同時發生了死鎖)來一起調式,當每個語句執行完畢後,我們看到鎖仍然保留下來了,它可以幫助我們識別出是哪個資源引起的死鎖。
下面列出了可以幫助我們監視鎖的檢視:
可以透過查詢V$LOCK字典檢視來確定鎖,如:
select * from v$lock ;
下面的SQL查詢可以用於確定鎖住資料庫物件的鎖:
select
c.owner,
c.object_name,
c.object_type,
b.sid,
b.serial#,
b.status,
b.osuser,
b.machine
from
v$locked_object a ,
v$session b,
dba_objects c
where
b.sid = a.session_id
and
a.object_id = c.object_id;
解決死鎖
安裝順序執行下面的修改,避免一致性訪問期間的死鎖問題:
設定事務一致性:我們需要確定一個隔離水平,在 儲存過程中可以使用“READ COMMITTED”或“SERIALIZABLE”,我們需要考慮兩件事情:
設定事務可以在任何時間提交
相關表中行的讀取順序
Oracle資料庫隔離模式透過行級鎖和Oracle資料庫多版本併發控制系統提供高階一致性和併發性(和高效能),READ COMMITTED模式可以提供更多的併發性,因為沒有重複讀,SERIALIZABLE隔離水平提供了更好的一致性,透過保護非重複讀實現,在一個讀寫事務執行不止一次查詢時這很重要,然而,SERIALIZABLE模式需要應用程式檢查“不能連續訪問”的錯誤,這樣就可以在有許多訪問相同資料的一致性事務的環境中大大減少吞吐量。
在我們的例子中,我們需要使用READ COMMITTED隔離水平,原因如下:
我們需要獲取由另一個事務提交的查詢返回的行,不僅僅是獲取剛開始的事務返回的行。
如果我們將隔離水平設為SERIALIZABLE,將會獲得一個“事務無法按順序訪問”的錯誤,因為我們想要修改的資料已經被另一個事務修改了。
在儲存過程中我們放入下面的語句:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
明確鎖定資料:Oracle資料庫總是執行必要的鎖確保資料的併發性、完整性和語句級讀一致性,但在我們的例子中,我們需要獨佔訪問資源,為了處理它的語句,事務獨佔訪問資源,不要等待其他事務完成。
我將會用一個例子來解釋,在我們的案例中,需要刪除一個業務物件System,為了刪除這個物件,首先我們需要刪除System子表中的所有資料,現在進入其中一個子表,我們在子表上建立一個關於刪除的觸發器,這個觸發器更新主表System的資料並鎖住它,接下來進入刪除操作,當我們想刪除System表中的資料時,就會出現死鎖,因為它已經被前面子表上的觸發器給鎖住了,為了避免出現這種情況,在刪除操作開始之前,我們提供一個行獨佔鎖鎖住System表來解決這個問題。命令如下:
LOCK TABLE ODNQTSY IN ROW EXCLUSIVE MODE;
並行索引和查詢處理:Oracle資料庫使用索引增強SQL查詢的效能,這有助於我們執行DML操作,如插入、更新和刪除,做這些動作的時間將會極具減少了。
並行索引將會讓最佳化器思考執行並行查詢時使用索引,這是避免死鎖的一個方法,當索引重建後,Oracle將會允許多個DML操作發生在同一個索引上,在索引上啟用並行操作的語法如下:
ALTER INDEX PARALLEL;
使用並行查詢選項的最大好處是直接路徑讀取,因此需要的latch就更少了,同樣,並行執行大大減少了資料密集型業務的響應時間。
並行執行選項可以透過修改INIT.ORA檔案中的PARALLEL_AUTOMATIC_TUNING引數(設為TRUE)實現資料庫級別的啟用。
parallel_automatic_tuning=TRUE
外來鍵上的索引:外來鍵上如果沒有建立索引會引發兩個問題,第一個是如果你更新父記錄主鍵或刪除父記錄,子表的外來鍵沒有索引時,會引發表級鎖;第二個問題是效能。
如果你試圖刪除父錶行,或更新父/子關聯中父錶行的鍵值,而子表的外來鍵上沒有索引時,Oracle將會嘗試在子表上獲得一個共享行級獨佔鎖,接下來如果有其它會話要修改子表,它將不得不等待在它前面的SRX鎖(共享行級獨佔鎖),這樣就形成了一個死鎖狀態。
下面的指令碼可以幫助我們識別沒有索引的外來鍵(FK)約束,從指令碼執行的輸出中,我們可以確定在外來鍵上建立索引將可以幫助我們改善效能,並且可以避免死鎖。
column columns format a20 word_wrapped
column table_name format a30 word_wrapped
select decode( b.table_name, NULL, '****', 'ok' ) Status,
a.table_name, a.columns, b.columns
from
( select substr(a.table_name,1,30) table_name,
substr(a.constraint_name,1,30) constraint_name,
max(decode(position, 1, substr(column_name,1,30),NULL)) ||
max(decode(position, 2,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 3,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 4,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 5,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 6,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 7,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 8,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 9,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,10,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,11,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,12,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,13,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,14,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,15,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,16,', '||substr(column_name,1,30),NULL)) columns
from user_cons_columns a, user_constraints b
where a.constraint_name = b.constraint_name
and b.constraint_type = 'R'
group by substr(a.table_name,1,30), substr(a.constraint_name,1,30) ) a,
( select substr(table_name,1,30) table_name, substr(index_name,1,30) index_name,
max(decode(column_position, 1, substr(column_name,1,30),NULL)) ||
max(decode(column_position, 2,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 3,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 4,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 5,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 6,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 7,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 8,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 9,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,10,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,11,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,12,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,13,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,14,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,15,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,16,', '||substr(column_name,1,30),NULL)) columns
from user_ind_columns
group by substr(table_name,1,30), substr(index_name,1,30) ) b
where a.table_name = b.table_name (+)
and b.columns (+) like a.columns || '%'
外來鍵的級聯刪除:在我們的案例中,已經使用“級聯刪除選項(On Delete Cascade)”建立了一些外來鍵約束,這樣會引發死鎖問題,原因是在我們的刪除事務中,我們明確地刪除子表中的資料,然後再刪除主表中的資料,因此在子表上就已經存在一個鎖了,在刪除主表之前,我們想再刪除子表一次,因此導致的死鎖。
為了解決這個問題,我們移除了“級聯刪除選項(On Delete Cascade)”,這樣就修復了死鎖問題。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8484829/viewspace-544979/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle資料表死鎖的解決方法Oracle
- 解決Oracle死鎖的快捷方法Oracle
- oracle死鎖測試與解決Oracle
- SQ死鎖及死鎖的解決
- 即刻殺死資料庫鎖資料庫
- (資料庫十)資料庫中的鎖機制以及死鎖產生的原因及解決辦法資料庫
- 解決Oracle死鎖問題步驟Oracle
- ORACLE ERP解決死鎖的方案Oracle
- oracle 死鎖解決方法一例Oracle
- MySQL 死鎖解決MySql
- MySQL解決死鎖MySql
- 關於資料庫死鎖問題的解釋資料庫
- oracle 死鎖表解決方法Oracle
- Oracle觸發器死鎖問題解決Oracle觸發器
- Oracle死鎖的檢視以及解決辦法Oracle
- 面試:什麼是死鎖,如何避免或解決死鎖;MySQL中的死鎖現象,MySQL死鎖如何解決面試MySql
- 死鎖檢測及解決
- oracle 死鎖Oracle
- oracle 資料庫的鎖Oracle資料庫
- MySQL的index merge(索引合併)導致資料庫死鎖分析與解決方案MySqlIndex索引資料庫
- 資料庫死鎖排查思路分享(糾正篇)資料庫
- 殺死Oracle死鎖程式Oracle
- MySQL死鎖分析與解決之路MySql
- 什麼是死鎖?如何解決死鎖?
- 轉載oracle資料庫鎖Oracle資料庫
- mysql慢查詢,死鎖解決方案MySql
- SQLserver 程式被死鎖問題解決SQLServer
- innodb_lock_monitor解決mysql死鎖MySql
- 由Oracle觸發器死鎖及行級鎖限制所衍生的解決方案Oracle觸發器
- 檢視oracle死鎖程式並結束死鎖Oracle
- MySQL資料庫-鎖詳解MySql資料庫
- 檢視MySql資料庫鎖,並殺死對應程式MySql資料庫
- 有關於SQL Server資料庫死鎖的分析(轉)SQLServer資料庫
- Oracle 死鎖處理Oracle
- Oracle死鎖處理Oracle
- ORACLE死鎖檢測Oracle
- Oracle資料庫資料鎖機制解析(zt)Oracle資料庫
- 例項詳解 Java 死鎖與破解死鎖Java