SqlServer 并发事务:死锁跟踪(二)确定死锁锁定的资源

--测试示例:
CREATE TABLE mytest  
(  
    id  INT,  
    name    VARCHAR(20),  
    info    VARCHAR(20),  
)  

INSERT INTO mytest VALUES(1,'kk',null),(2,'mm',null)  



--【现在测试只有非聚集索引的】
CREATE NONCLUSTERED INDEX IX_mytest_id ON DBO.mytest(id)  


--打开跟踪标志
DBCC TRACEON(1222,-1)


--分别打开个窗口,先执行事务窗口【1】,再执行事务窗口【2】
--事务窗口【1】 
BEGIN TRAN  
	PRINT @@SPID
    update dbo.mytest set info='A' where id =1  
    waitfor delay '00:00:10'  
    update dbo.mytest set info='B' where id =2  
ROLLBACK TRAN  


--事务窗口【2】 
BEGIN TRAN  
	PRINT @@SPID
    update dbo.mytest set info='C' where id =2  
    select * from dbo.mytest where id =1
ROLLBACK TRAN  


--session=61 成为死锁牺牲品



--打开SqlServer日志,几个地方可以看到锁定的资源信息。



这个RID具体是哪行数据在争用导致死锁??


--找到主要信息
waitresource=RID: 7:1:786:0
这是一个堆表,db_id=7,fileId=1,pageId=786,Slot = 0


--【方法一】查看数据页的信息
DBCC TRACEON(3604)
DBCC PAGE(TEST,1,786,3)

PAGE: (1:786)     

 

Slot 0 Offset 0x1008Length 19

 

Record Type = PRIMARY_RECORD         Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS

Record Size = 19                    

Memory Dump @0x62DAD008

 

00000000:   30000800 01000000 04000802 00110013 †0...............        

00000010:   006b6b†††††††††††††††††††††††††††††††.kk                     

 

Slot 0 Column 67108865 Offset 0x0 Length 0 Length (physical) 0

DROPPED = NULL                      

Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4

id = 1                              

Slot 0 Column 2 Offset 0x11 Length 2 Length (physical) 2

name = kk                           

Slot 0 Column 3 Offset 0x0 Length 0 Length (physical) 0

info =[NULL]                       

Slot 1 Offset 0x101eLength 19

 

Record Type =PRIMARY_RECORD         Record Attributes=  NULL_BITMAP VARIABLE_COLUMNS

Record Size = 19                    

Memory Dump @0x62DAD01E

 

00000000:   30000800 02000000 04000802 00110013 †0...............        

00000010:   006d6d†††††††††††††††††††††††††††††††.mm                     

 

Slot 1 Column 67108865Offset 0x0 Length 0 Length (physical) 0

DROPPED = NULL                      

Slot 1 Column 1 Offset 0x4Length 4 Length (physical) 4

id = 2                              

Slot 1 Column 2 Offset0x11 Length 2 Length (physical) 2

name = mm                           

Slot 1 Column 3 Offset 0x0Length 0 Length (physical) 0

info = [NULL]                       

 

DBCC 执行完毕。如果DBCC 输出了错误信息,请与系统管理员联系。


可以看到Slot = 0的数据内容为mytest(1,'kk',null)

可以确定,是这一行数据导致死锁。从t-sql脚本看是id=1导致的死锁。


--【方法二】更简单!直接select查询锁资源
SELECT * FROM [test].[dbo].mytest where %%lockres%% = '1:786:0'







--【现在创建聚集索引的情况】
CREATE CLUSTERED INDEX IX_mytest ON DBO.mytest(name)  
--CREATE NONCLUSTERED INDEX IX_mytest_id ON DBO.mytest(id)  



waitresource=KEY: 7:72057594050445312 (a791659675d9)
上面可以得出的信息:db_id=7;hobt_id=72057594050445312;keyhashvalue=(a791659675d9)

这下dbcc page()就就很难找了,虽然可以确定是哪个索引,但是确定不了具体锁资源
SELECT * FROM SYS.partitions WHERE hobt_id=72057594050445312  
SELECT * FROM SYS.indexes WHERE OBJECT_ID= 251147940 AND index_id=1  


--查看方法和上面rid查找的一样
SELECT * FROM [test].[dbo].mytest where %%lockres%% = '(a791659675d9)'

id	name	info
2	mm		NULL

--牺牲品是在等他id=2的行失败了。
--如果还想看看是哪个数据页,还是有办法查看的!
SELECT %%physloc%%,* FROM [test].[dbo].mytest where %%lockres%% = '(a791659675d9)'
SELECT sys.fn_physlocformatter(0xEE02000001000100)

--或者
select * from dbo.mytest cross apply sys.fn_PhysLocCracker(%%physloc%%)

%%physloc%%能找到数据行的物理地址,函数fn_physlocformatter再将地址解析为(file:page:slot)的格式。
在使用DBCC PAGE()查看

(注意:%%lockres%%这里取出的哈希值是锁管理的键值,与主键表的hashkey有出入。待了解!!)




 

 

其实确定死锁的具体资源也没什么用,更重要还是确定产生死锁的对象及脚本。

 

 

通常减少事务死亡的一些办法去解决:

按同一顺序访问对象

避免事务中的用户交互

保持事务简短并处于一个批处理中

使用较低的隔离级别

使用基于行版本控制的隔离级别

使用绑定连接

 

 

如果以上没法更改,试着其他的方法:

1 检查脚本是否有优化的空间进行优化

2 确定表中是否有聚集索引,创建聚集索引

3 是否有其他是索引,强制使用有利的索引

4 事务中的语句尽量短、处理少,不要执行太多语句以至时间太长(类似waitfor delay

5 尽量不要在一个事务中重复的读取和更改相同的数据,能一次读写完最好

 

 


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值