通过DBCC Page查看在SQL Server中哪行数据被锁住了?

如何查看被锁的是哪行数据?通过dbcc page可以。


要想明白这个问题:

首先,需要模拟阻塞问题,这里直接模拟了阻塞问题的一个比较极端的情况,就是死锁。

 

然后,需要知道如何监控死锁,否则,就算产生了死锁,你也不一定知道。这里在模拟死锁之前,通过SQL Profiler先来监控死锁问题。

 

接下来,我们可以通过sys.dm_tran_locks来获取更详细的阻塞信息。

 

最后,通过dbcc page来解析哪一行数据被锁住了。


下面就按照上面的步骤,一步一步来实现:

1、先监控死锁。

先选择SQL Profiler:


然后,新建跟踪,单击连接:


接下来,选择“事件选择”选项卡,点击“显示所有事件”复选框,在其中点击“Locks”事件,在“Deadlock graph”复选框,这样在发生死锁的时候,就会被监控到,而且以图像的方式显示死锁的信息,易于理解:



2、构造死锁。

先创建一个表

--建表
if OBJECT_ID('t1') is not null
   drop table t1
go

create table t1
(
id int primary key,
v varchar(20)
)


insert into t1
select 1 ,'aa' union all
select 2 ,'bb' union all
select 3 ,'cc' union all
select 4 ,'dd' union all
select 5 ,'ee' union all
select 6 ,'ff' 

开启会话X,在里面输入下面的代码:
--执行顺序.1
begin tran
   
   update t1
   set v = 'xx'
   where id = 3
--执行顺序.1


--执行顺序.3
   update t1
   set v = 'yy'
   where id = 6   
--执行顺序.3   

再次开启会话Y,在里面输入代码:

--执行顺序.2
begin tran

   update t1
   set v = 'mm'
   where id = 6

--执行顺序.2


--执行顺序.4
   update t1
   set v = 'nn'
   where id = 3  

--执行顺序.4

然后,按照先执行会话X中的执行顺序1,然后执行会话Y中的执行顺序2,执行会话X中的执行顺序3,执行会话Y中的执行顺序4,一步一步执行。

当执行完这4个步骤后,在会话X中,显示了死锁,且会话X的事务被回滚:



同时,能在SQL Profiler中看到监控到的死锁:



从这个图中,我们可以看到详细的死锁信息,打叉的表示被回滚的会话,把鼠标放到椭圆上,会显示导致死锁的,这个会话正在运行的sql语句。

在长方形的框中,可以看到两个会话要获取X锁,左边的会话拥有下面方框中的键锁,右边的会话拥有上面的键锁,而当左边的会话想要获取上面的键锁是,被阻塞住了,而当右边的会话想要获取下面的键锁时,也被阻塞了,于是整个图像中形成了一个循环,也就导致了死锁。


3、获取更详细的阻塞信息。

注意,上面提到的会话X,这里是53,而会话Y是55,这个可以从上面图中,椭圆形中的“服务器进程ID”获得。

通过通过sys.dm_tran_locks,可以获取到更为详细的阻塞信息。

select resource_type,
       resource_database_id,          --数据库id
       resource_description,          --资源描述
       resource_associated_entity_id, --资源关联实体id
       request_mode,                  --请求模式
       request_type,                  --请求类型
       request_status,                
       request_session_id,            --请求会话id
       request_owner_type             
from sys.dm_tran_locks
where request_session_id = 55



解析resource_associated_entity_id的值:

--1.查询resource_associated_entity_id的意义
select *
from sys.tables
where object_id = 837578022
/*
这个id是t1表

name	object_id
t1	    837578022
*/


--2.查询resource_associated_entity_id的意义
select *
from sys.partitions p
where p.hobt_id = 72057594041466880
/*
这个是表t1的一个b树

partition_id	    object_id	index_id	partition_number	hobt_id
72057594041466880	837578022	1	        1	      72057594041466880
*/

4、通过dbcc page来解析sys.dm_tran_locks中resource_description列的值:

resource_type	resource_database_id	resource_description
PAGE                10                      1:188
KEY	            10	                    (b9b173bbe8d5) 
KEY	            10	                    (98ec012aa510)

为了能解析 resource_description的值,需要建立一个表和一个存储过程,注意在存储过程中引用的1:188,就是上面sys.dm_tran_locks中的结果:

--3.这里创建一个表,用来存放dbcc page的结果  
if exists(select * from sys.tables where name = 'dbcc_page')  
   drop table dbcc_page  
go  
create table dbcc_page  
(  
ParentObject varchar(500),  
Object       varchar(2000),  
Field        varchar(1000),  
Value        nvarchar(max)  
)  
go


--创建一个存储过程
if exists(select * from sys.procedures where name = 'proc_dbcc_page')  
   drop procedure proc_dbcc_page  
go  
  
create procedure proc_dbcc_page  
as  
  
DBCC page(10,   --数据库id : 10
          1,    --文件id: 1
          188,  --页id: 188
          3) with tableresults  
  
go 

insert into dbcc_page
exec proc_dbcc_page
go

最后,我们查询一下,(b9b173bbe8d5)和(98ec012aa510),到底是哪一行数据

--查询(b9b173bbe8d5)和(98ec012aa510),到底是哪一行数据
;with t
as
(
select OBJECT,  
       Field,  
       value,
       case when charindex('Column',object) > 0
                 then charindex('Column',object)
            else charindex('Offset',object)
       end as substring_len
from dbcc_page dp
where Object like 'Slot%Column%' 
      or
      Field = 'KeyHashValue'
),

tt
as
(
select object, 
       field,
       value,
       cast(substring(object,len('Slot')+1,substring_len-len('Slot')-1) as int) as row
from t 
),

ttt
as
(
select object,
       field,
       value,
       row,    --第几行
       max(case when field = 'KeyHashValue' 
                     then value 
                 else ''
           end) over(partition by row) as KeyHashValue
from tt
)

select *
from ttt
where KeyHashValue in ('(b9b173bbe8d5)', '(98ec012aa510)')

下面的是查询结果:



从上图中,我们能很清楚的看到(b9b173bbe8d5)和(98ec012aa510),就是id为3、6的两行数据,这两行数据最后被会话55锁住了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值