/********************************************************************************
死鎖指兩個以上事務相互阻塞相互等待對方釋放它們的鎖,SQL Server會通過回滾其中一個事務並返回一個錯誤來自已解決阻塞問題,讓其他事務完成它們的工作。
****************************************************************************************/
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(索引):
begin
tran
update
t1
set
col2=col2+
'A'
where
col1=101
select
*
from
t2
where
col1=201
commit
tran
begin
tran
update
t2
set
col2=col2+
'B'
where
col1=203
select
*
from
t1
where
col1=103
commit
tran
/*
訊息 1205,層級 13,狀態 51,行 3
交易 (處理序識別碼 53) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。
*/
/*
3 103 C
*/
處理方法:
create
index
IX_t1_col1
on
t1(col1)
create
index
IX_t2_col1
on
t2(col1)
go
begin
tran
update
t1
set
col2=col2+
'A'
where
col1=101
select
*
from
t2
with
(
index
=IX_t2_col1)
where
col1=201
commit
tran
begin
tran
update
t2
set
col2=col2+
'B'
where
col1=203
select
*
from
t1
with
(
index
=IX_t1_col1)
where
col1=103
commit
tran
/*
ID Col1 Col2
1 201 X
(1 個資料列受到影響)
*/
/*
ID Col1 Col2
3 103 C
(1 個資料列受到影響)
*/
死鎖2(訪問表順序):
begin
tran
update
t1
set
col1=col1+1
where
ID=1
select
col1
from
t2
where
ID=1
commit
tran
begin
tran
update
t2
set
col1=col1+1
where
ID=1
select
col1
from
t1
where
ID=1
commit
tran
/*
col1
201
(1 個資料列受到影響)
*/
/*
col1
訊息 1205,層級 13,狀態 51,行 1
交易 (處理序識別碼 54) 在 鎖定 資源上被另一個處理序鎖死並已被選擇作為死結的犧牲者。請重新執行該交易。
*/
處理方法:
begin
tran
update
t1
set
col1=col1+1
where
ID=1
select
col1
from
t2
where
ID=1
commit
tran
begin
tran
select
col1
from
t1
where
ID=1
update
t2
set
col1=col1+1
where
ID=1
commit
tran
死鎖3(單表):
while 1=1
update
T1
set
col1=203-col1
where
ID=2
declare
@i nvarchar(20)
while 1=1
set
@i=(
select
col2
from
T1
with
(
index
=IX_t1_col1)
where
Col1=102);
/*
訊息 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 該事件發生了死鎖