-- 死鎖 /* ***************************************************************************************************************************************************** 死鎖指兩個以上事務相互阻塞相互等待對方釋放它們的鎖,SQL Server會通過回滾其中一個事務並返回一個錯誤來自已解決阻塞問題,讓其他事務完成它們的工作。 整理人:中国风(Roy) 日期:2008.07.20 ***************************************************************************************************************************************************** */ set nocount on ; if object_id ( ' T1 ' ) is not null drop table T1 go create table T1(ID int primary key ,Col1 int ,Col2 nvarchar ( 20 )) insert T1 select 1 , 101 , ' A ' insert T1 select 2 , 102 , ' B ' insert T1 select 3 , 103 , ' C ' go if object_id ( ' T2 ' ) is not null drop table T2 go create table T2(ID int primary key ,Col1 int ,Col2 nvarchar ( 20 )) insert T2 select 1 , 201 , ' X ' insert T2 select 2 , 202 , ' Y ' insert T2 select 3 , 203 , ' Z ' go 生成表數據: /* T1: ID Col1 Col2 ----------- ----------- -------------------- 1 101 A 2 101 B 3 101 C T2: ID Col1 Col2 ----------- ----------- -------------------- 1 201 X 2 201 Y 3 201 Z */ 防止死鎖: 1 、 最少化阻塞。阻塞越少,發生死鎖機會越少 2 、 在事務中按順序訪問表(以上例子:死鎖2) 3 、 在錯誤處理程式中檢查錯誤1205並在錯誤發生時重新提交事務 4 、 在錯誤處理程式中加一個過程將錯誤的詳細寫入日誌 5 、 索引的合理使用(以上例子:死鎖1、死鎖3) 當發生死鎖時,事務自動提交,可通過日誌來監視死鎖 死鎖1(索引): -- 連接窗口1 -- 1步: begin tran update t1 set col2 = col2 + ' A ' where col1 = 101 -- 3步: select * from t2 where col1 = 201 commit tran -- 連接窗口2 -- 2步: begin tran update t2 set col2 = col2 + ' B ' where col1 = 203 -- 4步: select * from t1 where col1 = 103 commit tran -- 連接窗口1:收到死鎖錯誤,連接窗口2得到結果: /* 訊息 1205,層級 13,狀態 51,行 3 交易 (處理序識別碼 53) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。 */ -- 連接窗口2:得到結果 /* ----------- ----------- -------------------- 3 103 C */ 處理方法: -- 在t1、t2表的col1條件列建索引 create index IX_t1_col1 on t1(col1) create index IX_t2_col1 on t2(col1) go -- 連接窗口1 -- 1步: begin tran update t1 set col2 = col2 + ' A ' where col1 = 101 -- 3步: select * from t2 with ( index = IX_t2_col1) where col1 = 201 -- 因表數據少,只能指定索引提示才能確保SQL Server使用索引 commit tran -- 連接窗口2 -- 2步: begin tran update t2 set col2 = col2 + ' B ' where col1 = 203 -- 4步: select * from t1 with ( index = IX_t1_col1) where col1 = 103 -- 因表數據少,只能指定索引提示才能確保SQL Server使用索引 commit tran -- 連接窗口1: /* ID Col1 Col2 ----------- ----------- -------------------- 1 201 X (1 個資料列受到影響) */ -- 連接窗口2 /* ID Col1 Col2 ----------- ----------- -------------------- 3 103 C (1 個資料列受到影響) */ 死鎖2(訪問表順序): -- 連接窗口1: -- 1步: begin tran update t1 set col1 = col1 + 1 where ID = 1 -- 3步: select col1 from t2 where ID = 1 commit tran -- 連接窗口2: -- 2步: begin tran update t2 set col1 = col1 + 1 where ID = 1 -- 4步 select col1 from t1 where ID = 1 commit tran -- 連接窗口1: /* col1 ----------- 201 (1 個資料列受到影響) */ -- 連接窗口2: /* col1 ----------- 訊息 1205,層級 13,狀態 51,行 1 交易 (處理序識別碼 54) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。 */ 處理方法: -- 改變訪問表的順序 -- 連接窗口1: -- 1步: begin tran update t1 set col1 = col1 + 1 where ID = 1 -- 3步: select col1 from t2 where ID = 1 commit tran -- 連接窗口2: -- 2步: begin tran select col1 from t1 where ID = 1 -- 會等待連接窗口1提交 -- 4步 update t2 set col1 = col1 + 1 where ID = 1 commit tran 死鎖3(單表): -- 連接窗口1: while 1 = 1 update T1 set col1 = 203 - col1 where ID = 2 -- 連接窗口2: declare @i nvarchar ( 20 ) while 1 = 1 set @i = ( select col2 from T1 with ( index = IX_t1_col1) where Col1 = 102 ); -- 因表數據少,只能指定索引提示才能確保SQL Server使用索引 -- 連接窗口1 /* 訊息 1205,層級 13,狀態 51,行 4 交易 (處理序識別碼 53) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。 */ 處理方法: 1 、刪除col1上的非聚集索引,這樣影響SELECT速度,不可取. drop index IX_t1_col1 on t1 2 、建一個覆蓋索引 A、 drop index IX_t1_col1 on t1 B、 create index IX_t1_col1_col2 on t1(col1,col2) 通過SQL Server Profiler查死鎖信息: 啟動SQL Server Profiler——連接實例——事件選取範圍——顯示所有事件 選擇項: TSQL——SQL:StmtStarting Locks——Deadlock graph(這是SQL2005新增事件,生成包含死鎖信息的xml值) ——Lock:DeadlockChain 死鎖鏈中的進程產生該事件,可標識死鎖進程的ID並跟蹤操作 ——Lock:Deadlock 該事件發生了死鎖
死锁分析整理
最新推荐文章于 2022-11-27 01:09:29 发布