您的位置:首页 > 数据库

SQL分析死锁并处理

2009-05-13 16:09 393 查看
SQL分析死锁并处理 From CSDN.net

原帖地址:http://topic.csdn.net/u/20080721/20/15a60db6-34b5-4ea1-b392-11c42270aaab.html

--死鎖

/******************************************************************************************************************************************************

死鎖指兩個以上事務相互阻塞相互等待對方釋放它們的鎖,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 該事件發生了死鎖
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: