DeadLock in Oracle Database
死鎖
在事務執行高峰期,由於DDL、DML使用鎖資源十分頻繁,爭用時甚至會發生死鎖,阻塞的鎖可能導致系統延遲,甚至長時間不響應,影響業務系統的正常執行。若死鎖頻頻發生,則有可能是應用設計不當。這裡暫且初步整理下鎖爭用的有關資料。
1.鎖介紹
概述
鎖:併發訪問、更新時容易出現
概念:當資料庫物件正在被其他程序或使用者修改時,可以保護它不被修改
結構:“排隊”的佇列,先到先服務,序列工作
功能:
- 堅持一致性和完整性
- 佇列結構管理請求的會話
- 自動處理鎖機制
- 鎖的持續時間等於被提交事務的長度或處理時間
型別
DDL
- 在修改過程中保護模式物件
- DDL鎖,由Oracle自動釋出和釋放
DML
- 在事務處理過程中保護物件
- 當釋出rollback或commit時,認為完成了事務
內部鎖
- 由Oracle管理,以保護內部資料庫結構,如資料檔案
模式
鎖模式描述 …
鎖模式和DML語句 …
鎖模式和DDL語句 …
級別
資料庫級別
鎖定資料庫以禁止任何新會話和新事務,可以分為以下三種類型。
ALTER SYSTEM ENABLE RESTRICTED SESSION * 使資料庫進入限制模式 * 僅有RESTRICTED SESSION許可權使用者才能登陸 * 已經登陸的會話不受此印象 * 登陸的使用者可以正常進行DDL/DML操作 ALTER SYSTEM QUIESCE RESTRICTED * 使資料庫進入靜默的限制模式 * 從使用者的活動中鎖定資料庫,鎖定所有操作(處於等待狀態),直到UNQUICESCE * 不允許非特權使用者登陸 * 特權使用者可以正常進行操作 ALTER DATABASE OPEN READ ONLY * 使資料庫以只讀模式開啟 * UNDO段處於離線狀態 * 不允許任何更新、事務操作
表級別
- 通過DML或者LOCK語句發出
行級別
- DML更新一行或多行時
- Oracle支援的最低級別
- SELECT … FOR UPDATE只鎖定返回的行
列級別
- Oracle不支援
鎖語句
LOCK語法
LOCK TABLE
[ schema.]{table | view} [@dblink]
[, [schema.]{table | view} [@dblink] ] ...
IN lockmode MODE
[ NOWAIT]
示例
* SHARE(S) * ROW SHARE(RS) * ROW EXCLUSIVE(RX) * SHARE ROW EXCLUSIVE(SRX) * EXCLUSIVE(X) * SELECT ... FOR UPDATE
2.死鎖日誌
警告日誌
Wed Feb 27 09:34:58 2013
ORA-000060: Deadlock detected. More info in file /u1/PROD/prodora/proddb/9.2.0/admin/PROD_erpprod/udump/prod_ora_4513878.trc.
跟蹤日誌
... ...
*** 2013-02-11 03:01:37.846
*** SESSION ID:(25.18) 2013-02-11 03:01:37.846
Undo Segment 11 Onlined
*** 2013-02-11 08:41:27.866
Undo Segment 19 Onlined
*** 2013-02-16 08:46:16.482
Undo Segment 134 Onlined
*** 2013-02-16 09:55:31.314
Undo Segment 195 Onlined
*** 2013-02-27 09:34:58.033
DEADLOCK DETECTED
Current SQL statement for this session:
UPDATE FND_CONCURRENT_REQUESTS SET PP_END_DATE = SYSDATE, POST_REQUEST_STATUS = 'E' WHERE REQUEST_ID = :B1
----- PL/SQL Call Stack -----
object line object
handle number name
700000095f756d0 67 package body APPS.FND_CP_OPP_CMD
70000008caf2ea0 1 anonymous block
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
TX-0159001e-000075b3 24 25 X 24 25 X
session 25: DID 0001-0018-00000006 session 25: DID 0001-0018-00000006
Rows waited on:
Session 25: obj - rowid = 00009050 - AAAJBQAAmAAAKPzAAG
(dictionary objn - 36944, file - 38, block - 41971, slot - 6)
Information on the OTHER waiting sessions:
End of information on OTHER waiting sessions.
... ...
3.死鎖情形模擬
若在請求鎖資源時出現迴圈等待,則產生死鎖現象。如下,以列出順序先後執行更新操作。
1.獲取並保持鎖,如LOCK1,且為排他鎖,鎖定更新行1:
SQL(49,180)>update dt_char set name = '1A' where id = 1;
1 row updated.
2.獲取並保持鎖,如LOCK2,且為排他鎖,鎖定更新行2:
SQL(462,13)> update dt_char set name = '2B' where id = 2;
1 row updated.
3.請求更新行2,因處於等待,等待鎖LOCK2
SQL(49,180)>update dt_char set name = '2A' where id = 2;
4.請求更新行1,因處於等待,等待鎖LOCK1
SQL(462,13)> update dt_char set name = '1B' where id = 1;
此時,會話(49,180)和(462,13)在鎖資源LOCK1和LOCK2上存在迴圈等待的情形,故出現死鎖,3中的語句終止;此時4中的語句處於等待狀態。
SQL(49,180)>update dt_char set name = '2A' where id = 2;
update dt_char set name = '2A' where id = 2
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
出現死鎖時,系統會
4.死鎖解決方案
ORA-00060 deadlock detected while waiting for resource
Cause: Your session and another session are waiting for a resource locked by the other. This condition is known as a deadlock. To resolve the deadlock, one or more statements were rolled back for the other session to continue work.
Action: Either:
- Enter a ROLLBACK statement and re-execute all statements since the last commit or
- Wait until the lock is released, possibly a few minutes, and then re-execute the rolled back statements.
除了執行ROLLBACK,或者等待鎖資源釋放,並重新執行所需要的語句外;還有一種方案就是清理掉死鎖中阻塞的一方的資料庫會話。
--生成kill session指令碼,殺掉死鎖中阻塞一方的會話
--ALTER SYSTEM KILL SESSION 'sid,serial#';
SELECT 'alter system kill session ''' || SID || ',' || SERIAL# || ''';' "Deadlock"
FROM V$SESSION
WHERE SID IN (SELECT SID FROM V$LOCK WHERE BLOCK = 1);
DDL Lock
DDL語句在釋出時為獲取資料物件的內部結構而需要排他鎖,如果鎖不可用則會更新失敗。
1.直接釋出ALTER TABLE語句
建立SQL*Plus
會話(27,0),發出ALTER TABLE語句:
SQL> SELECT * FROM V$MYSTAT WHERE ROWNUM = 1;
SID STATISTIC# VALUE
---------- ---------- ----------
27 0 0
SQL> desc dt_char;
Name Null? Type
----------------------------------------- -------- ----------------------------
NAME CHAR(10)
SQL> alter table dt_char modify (name varchar(20));
Table altered.
SQL> desc dt_char;
Name Null? Type
----------------------------------------- -------- ----------------------------
NAME VARCHAR2(20)
2.有DML更新表資料時釋出DDL語句
預設
新開一個SQL*Plus
會話(513,22540),發出UPDATE語句:
SQL> SELECT * FROM V$MYSTAT WHERE ROWNUM = 1;
SID STATISTIC# VALUE
---------- ---------- ----------
513 22540 0
SQL> update dt_char set name = 'DDL Lock';
0 rows updated.
此時,在會話(27,0)中再次釋出ALTER TABLE語句:
SQL> alter table dt_char modify (name char(10));
alter table dt_char modify (name char(10))
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
此時,提示要求更新的表結構正處於繁忙狀態(被其他會話佔用),因不願意等待鎖釋放或者等待超時,故更新失敗。
檢視哪些物件處於爭用之中:
SQL> SELECT lo.session_id,
s.serial#,
lo.oracle_username,
o.owner,
o.object_name,
o.object_type,
decode(lo.locked_mode,
0,
'None', /* Mon Lock equivalent */
1,
'Null', /* N */
2,
'Row-S (SS)', /* L */
3,
'Row-X (SX)', /* R */
4,
'Share', /* S */
5,
'S/Row-X (SSX)', /* C */
6,
'Exclusive', /* X */
lo.locked_mode) locked_mode
FROM v$locked_object lo,
dba_objects o,
v$session s
WHERE lo.object_id = o.object_id
AND s.sid = lo.session_id;
SESSION_ID SERIAL# ORACLE_USERNAME OWNER OBJECT_NAME OBJECT_TYPE LOCKED_MODE
---------- ---------- ---------------- ---------- ------------ ------------ -----------
513 22540 DEV DEV DT_CHAR TABLE Row-X (SX)
從以上查詢可以看出,表DEV.DT_CHAR正在被會話(513.22540)佔用,鎖模式為Row-X,即排他鎖,為了更新,在某個事務中鎖定了行,則不允許其他事務鎖定這個表。
在這個例子中,釋出的DML後,已經獲取了鎖,並鎖定了表DEV.DT_CHAR,因沒有釋出ROLLBACK、COMMIT,該會話一直持有鎖資源。
指定TIMEOUT
在會話(27,0)中,釋出超時為30s:
[email protected](27,0)> alter session set ddl_lock_timeout=30; --DDL_LOCK_TIMEOUT引數值預設為0
Session altered.
[email protected](27,0)> alter table dt_char modify (name char(10)); --處於等待狀態,超時30s
此時,若在釋出DDL時起30s內,會話(513,22540)釋放鎖資源,則DDL可以更新成功:
[email protected](513,22540)> commit;
Commit complete.
[email protected](27,0)> alter table dt_char modify (name char(10)); --處於等待狀態,超時30s
Table altered.
否則,DDL失敗:
[email protected](27,0)> alter table dt_char modify (name char(10)); --處於等待狀態,超時30s
alter table dt_char modify (name char(10))
*
ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
DML Lock
1.事務和儲存點
原始資料:
SQL> select * from dt_char;
NAME
----------
1
2
3
4
5
更新行:
SQL> update dt_char set name = '1A' where name = '1';
1 row updated.
SQL> select * from dt_char;
NAME
----------
1A
2
3
4
5
建立儲存點,用來控制事務
SQL> savepoint A;
Savepoint created.
更新行:
SQL> update dt_char set name = '2A' where name = '2';
1 row updated.
SQL> select * from dt_char;
NAME
----------
1A
2A
3
4
5
回滾到儲存點A,此時在A之前的鎖沒有釋放,在A之後的鎖則被釋放,更新將會回滾到儲存A(若不指定儲存點,則回滾到更新的初始狀態):
SQL> rollback to savepoint A;
Rollback complete.
SQL> select * from dt_char;
NAME
----------
1A
2
3
4
5
常用指令碼
查詢當前會話ID
--查詢當前會話ID
SELECT * FROM V$MYSTAT WHERE ROWNUM = 1;
查詢會話鎖
--查詢會話鎖
SELECT * FROM DBA_LOCKS WHERE SESSION_ID IN (513);
檢測鎖爭用
--request:如果request值非0,則表示在等待一個鎖
--block:如果block為1,則表示此會話持有一個鎖,並阻塞別人獲得此鎖
SELECT *
FROM V$LOCK
WHERE BLOCK = 1
OR REQUEST > 0;
被鎖定的物件
--被鎖定的物件
SELECT * FROM V$LOCKED_OBJECT;
僅列出使用者所保持的鎖
--僅列出使用者所保持的鎖
SELECT S.USERNAME,
L.SESSION_ID,
L.LOCK_TYPE,
L.MODE_HELD,
L.MODE_REQUESTED,
L.LOCK_ID1,
L.LOCK_ID2,
L.LAST_CONVERT,
L.BLOCKING_OTHERS
FROM V$SESSION S, DBA_LOCKS L
WHERE S.USERNAME IS NOT NULL
AND (S.SID = L.SESSION_ID AND L.MODE_REQUESTED != 'NONE')
OR (S.SID = L.SESSION_ID AND L.MODE_REQUESTED = 'NONE' AND
L.MODE_HELD != 'Share' AND
(LOCK_ID1, LOCK_ID2) IN
(SELECT A.LOCK_ID1, A.LOCK_ID2
FROM DBA_LOCKS A
WHERE A.MODE_REQUESTED != 'NONE'
AND A.LOCK_ID1 = L.LOCK_ID1
AND A.LOCK_ID2 = L.LOCK_ID2))
ORDER BY 6, 7, 5;
哪些物件處於爭用中
--v$locked_object
--哪些物件處於爭用中
SELECT LO.SESSION_ID,
S.SERIAL#,
LO.ORACLE_USERNAME,
S.PROCESS,
S.PROGRAM,
O.OWNER,
O.OBJECT_NAME,
O.OBJECT_TYPE,
DECODE(LO.LOCKED_MODE,
0,
'None', /* Mon Lock equivalent */
1,
'Null', /* N */
2,
'Row-S (SS)', /* L */
3,
'Row-X (SX)', /* R */
4,
'Share', /* S */
5,
'S/Row-X (SSX)', /* C */
6,
'Exclusive', /* X */
LO.LOCKED_MODE) LOCKED_MODE
FROM V$LOCKED_OBJECT LO, DBA_OBJECTS O, V$SESSION S
WHERE LO.OBJECT_ID = O.OBJECT_ID
AND S.SID = LO.SESSION_ID
AND S.SID IN (336, 1360);
死鎖檢測
--dba_blockers
--阻塞其他使用者的會話的id
SELECT * FROM DBA_BLOCKERS;
--dba_waiters
--顯示等待將被阻塞會話釋放鎖的會話id
SELECT * FROM DBA_WAITERS;
--使用dba_waiters檢視
資訊格式:Blocker|Waiter(sid,serial#,username,sql)
SELECT 'Blocker(' || BW.HOLDING_SESSION || ':' || SB.USERNAME ||
') - SQL: ' || BQ.SQL_TEXT BLOCKERS,
'Waiter(' || BW.WAITING_SESSION || ':' || SW.USERNAME || ') - SQL: ' ||
WQ.SQL_TEXT BLOCKERS
FROM DBA_WAITERS BW,
V$SESSION SB,
V$SESSION SW,
V$SQLAREA BQ,
V$SQLAREA WQ
WHERE BW.HOLDING_SESSION = SB.SID
AND BW.WAITING_SESSION = SW.SID
AND SB.PREV_SQL_ADDR = BQ.ADDRESS
AND SW.SQL_ADDRESS = WQ.ADDRESS
AND BW.MODE_HELD <> 'None';
--使用dba_locks檢視
--資訊格式:Blocker|Waiter(sid,serial#,username,sql)
SELECT DISTINCT 'Blocker(' || LB.SESSION_ID || ',' || SB.SERIAL# || ':' ||
SB.USERNAME || ') - SQL: ' || BQ.SQL_TEXT BLOCKERS,
'Waiter(' || LW.SESSION_ID || ',' || SW.SERIAL# ||
SW.USERNAME || ') - SQL: ' || WQ.SQL_TEXT BLOCKERS
FROM DBA_LOCKS LB,
V$SESSION SB,
DBA_LOCKS LW,
V$SESSION SW,
V$SQL BQ,
V$SQL WQ
WHERE LB.SESSION_ID = SB.SID
AND LW.SESSION_ID = SW.SID
AND SB.PREV_SQL_ADDR = BQ.ADDRESS
AND SW.SQL_ADDRESS = WQ.ADDRESS
AND LB.LOCK_ID1 = LW.LOCK_ID1
AND SW.LOCKWAIT IS NOT NULL
AND SB.LOCKWAIT IS NULL
AND LB.BLOCKING_OTHERS = 'Blocking';
生成kill session指令碼
--生成kill session指令碼,殺掉死鎖中阻塞一方的會話
--ALTER SYSTEM KILL SESSION 'sid,serial#';
SELECT 'alter system kill session ''' || SID || ',' || SERIAL# || ''';' "Deadlock"
FROM V$SESSION
WHERE SID IN (SELECT SID FROM V$LOCK WHERE BLOCK = 1);
檢視導致死鎖的SQL
--導致死鎖的SQL
SELECT S.SID, Q.SQL_TEXT
FROM V$SQLTEXT Q, V$SESSION S
WHERE Q.ADDRESS = S.SQL_ADDRESS
AND S.SID = &SID
ORDER BY PIECE;
延伸閱讀
Reference
- Database Error Message
- Oracle 9i資料庫效能優化與調整