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


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

要想明白这个问题:

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

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

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

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

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

1、先监控死锁。

先选择SQL Profiler:

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

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

2、构造死锁。

先创建一个表


  1. --建表
  2. if OBJECT_ID('t1') is not null
  3. drop table t1
  4. go
  5. create table t1
  6. (
  7. id int primary key,
  8. v varchar(20)
  9. )
  10. insert into t1
  11. select 1 ,'aa' union all
  12. select 2 ,'bb' union all
  13. select 3 ,'cc' union all
  14. select 4 ,'dd' union all
  15. select 5 ,'ee' union all
  16. select 6 ,'ff'

开启会话X,在里面输入下面的代码:


  1. --执行顺序.1
  2. begin tran
  3. update t1
  4. set v = 'xx'
  5. where id = 3
  6. --执行顺序.1
  7. --执行顺序.3
  8. update t1
  9. set v = 'yy'
  10. where id = 6
  11. --执行顺序.3

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


  1. --执行顺序.2
  2. begin tran
  3. update t1
  4. set v = 'mm'
  5. where id = 6
  6. --执行顺序.2
  7. --执行顺序.4
  8. update t1
  9. set v = 'nn'
  10. where id = 3
  11. --执行顺序.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,可以获取到更为详细的阻塞信息。


  1. select resource_type,
  2. resource_database_id, --数据库id
  3. resource_description, --资源描述
  4. resource_associated_entity_id, --资源关联实体id
  5. request_mode, --请求模式
  6. request_type, --请求类型
  7. request_status,
  8. request_session_id, --请求会话id
  9. request_owner_type
  10. from sys.dm_tran_locks
  11. where request_session_id = 55

解析resource_associated_entity_id的值:


  1. --1.查询resource_associated_entity_id的意义
  2. select *
  3. from sys.tables
  4. where object_id = 837578022
  5. /*
  6. 这个id是t1表
  7. name object_id
  8. t1 837578022
  9. */
  10. --2.查询resource_associated_entity_id的意义
  11. select *
  12. from sys.partitions p
  13. where p.hobt_id = 72057594041466880
  14. /*
  15. 这个是表t1的一个b树
  16. partition_id object_id index_id partition_number hobt_id
  17. 72057594041466880 837578022 1 1 72057594041466880
  18. */

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


  1. resource_type resource_database_id resource_description
  2. PAGE 10 1:188
  3. KEY 10 (b9b173bbe8d5)
  4. KEY 10 (98ec012aa510)

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


  1. --3.这里创建一个表,用来存放dbcc page的结果
  2. if exists(select * from sys.tables where name = 'dbcc_page')
  3. drop table dbcc_page
  4. go
  5. create table dbcc_page
  6. (
  7. ParentObject varchar(500),
  8. Object varchar(2000),
  9. Field varchar(1000),
  10. Value nvarchar(max)
  11. )
  12. go
  13. --创建一个存储过程
  14. if exists(select * from sys.procedures where name = 'proc_dbcc_page')
  15. drop procedure proc_dbcc_page
  16. go
  17. create procedure proc_dbcc_page
  18. as
  19. DBCC page(10, --数据库id : 10
  20. 1, --文件id: 1
  21. 188, --页id: 188
  22. 3) with tableresults
  23. go
  24. insert into dbcc_page
  25. exec proc_dbcc_page
  26. go

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


  1. --查询(b9b173bbe8d5)和(98ec012aa510),到底是哪一行数据
  2. ;with t
  3. as
  4. (
  5. select OBJECT,
  6. Field,
  7. value,
  8. case when charindex('Column',object) > 0
  9. then charindex('Column',object)
  10. else charindex('Offset',object)
  11. end as substring_len
  12. from dbcc_page dp
  13. where Object like 'Slot%Column%'
  14. or
  15. Field = 'KeyHashValue'
  16. ),
  17. tt
  18. as
  19. (
  20. select object,
  21. field,
  22. value,
  23. cast(substring(object,len('Slot')+1,substring_len-len('Slot')-1) as int) as row
  24. from t
  25. ),
  26. ttt
  27. as
  28. (
  29. select object,
  30. field,
  31. value,
  32. row, --第几行
  33. max(case when field = 'KeyHashValue'
  34. then value
  35. else ''
  36. end) over(partition by row) as KeyHashValue
  37. from tt
  38. )
  39. select *
  40. from ttt
  41. where KeyHashValue in ('(b9b173bbe8d5)', '(98ec012aa510)')

下面的是查询结果:

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

发布了416 篇原创文章 · 获赞 135 · 访问量 94万+

通过DBCC Page查看在SQL Server中哪行数据被锁住了?的更多相关文章

  1. .SQL Server中 image类型数据的比较

    原文:.SQL Server中 image类型数据的比较 在SQL Server中如果你对text.ntext或者image数据类型的数据进行比较.将会提示:不能比较或排序 text.ntext 和 ...

  2. 删除sql server中重复的数据

    原文:删除sql server中重复的数据 with list_numbers as( select Name, AuthorOrTime, Url, Price, EstimatePrice, Si ...

  3. sql Server中临时表与数据表的区别

    sql server 中临时表与数据表的区别 1.如何判断临时表和数据表已生成 --如何判断临时表是否已创建--- if exists(select * from tempdb..sysobjects ...

  4. 转:Sql Server中清空所有数据表中的记录

    如果要删除数据表中所有数据只要遍历一下数据库再删除就可以了,清除所有数据我们可以使用搜索出所有表名,构造为一条SQL语句进行清除了,这里我一一给各位同学介绍.   使用sql删除数据库中所有表是不难的 ...

  5. SQL Server中Table字典数据的查询SQL示例代码

    SQL Server中Table字典数据的查询SQL示例代码 前言 在数据库系统原理与设计(第3版)教科书中这样写道: 数据库包含4类数据: 1.用户数据 2.元数据 3.索引 4.应用元数据 其中, ...

  6. Sql Server中清空所有数据表中的记录

    Sql Server中清空所有数据表中的记录 清空所有数据表中的记录: 代码如下:exec sp_msforeachtable  @Command1 ='truncate table ?'删除所有数据 ...

  7. 从TXT文本文档向Sql Server中批量导入数据

    下面我们通过以下的简单的SQL语句即可实现数据的批量导入,代码如下: Bulk insert id From 'G:\文档\test.txt' With ( fieldterminator=',', ...

  8. SQL Server 中 ROWLOCK 行级锁

    一.ROWLOCK的使用 1.ROWLOCK行级锁确保,在用户取得被更新的行,到该行进行更新,这段时间内不被其它用户所修改.因而行级锁即可保证数据的一致性,又能提高数据操作的并发性. 2.ROWLOC ...

  9. Sql Server实现多行数据按分组用逗号分隔成一行数据

    例如,要将下面的数据 以GROUP_ID进行分组,一组一行,一组中的多个PRODUCT_ID用逗号分隔,select 出来成如下结果: 在Sql Server中,我目前想到的一种方法是写一个函数,如下 ...

随机推荐

  1. IIS URL Rewriting and ASP.NET Routing

    IIS URL Rewriting and ASP.NET Routing With the release of the URL Rewrite Module for IIS and the inc ...

  2. scroll-view组件实现下拉刷新, 拉到底加载更多

    官方文档已声明,即使在page.json和app.json中开启下拉刷新,scroll-view组件也是不支持的.但我们可以通过曲线救国的方法来实现 实现代码 // wxml <scroll-v ...

  3. 《你不知道的JavaScript(上)》笔记——this全面解析

    首先要理解调用位置: 调用位置就是函数在代码中被调用的位置(而不是声明的位置). 最重要的是要分析调用栈(就是为了到达当前执行位置所调用的所有函数). 我们关心的调用位置就在当前正在执行的函数的前一个 ...

  4. angular点击事件和表单事件

    <div style="text-align:center"> <h1> Welcome to {{ title }}! </h1> <b ...

  5. Linux 验证当前 Video0 不否是v4l设备 linux v4l 编程(1) Video 4 Linux 简介

    #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/types.h ...

  6. 19 Flutter 自定义AppBar 定义顶部Tab切换 底部Tab结合顶部Tab实现类似头条页面布局(27分36秒)

    Flutter AppBar自定义顶部导航按钮图标.颜色以及TabBar定义顶部Tab切换. leading:在标题前面显示的一个控件,在首页通常显示应用的logo:在其他界面通常显示为付汇按钮. t ...

  7. 18Flutter中的路由、路由替换、返回到根路由:

    路由: 正常跳转: Navigator.pushNamed(context,'/product');   路由替换: Navigator.pushReplacementNamed(context, ' ...

  8. 最简易的python web框架的后端实现

    1.源代码 #!/usr/bin/python #encoding=utf-8 from flask import json, Flask, request app = Flask(__name__) ...

  9. 123457123456#0#-----com.twoapp.KidsShiZi01--前拼后广--儿童宝宝识字jiemei

    com.twoapp.KidsShiZi01--前拼后广--儿童宝宝识字jiemei

  10. 云计算和 AWS 概述(一)

    目录 云计算基础 概念 优势 云计算分类 AWS简介 服务概述 AWS 核心服务 AWS 平台服务 AWS开发和操作服务 AWS 数据中心和可用区(AZ) 区域 可用区 区域名 AWS 云适应框架 ( ...