到了这篇,才是真正动手解决问题的时候,有了死锁之后就要分析死锁的原因,具体就是需要定位到具体的SQL语句上。那么如何发现产生死锁的问题本质呢?下面这篇讲的非常细了,还提到了不少实用的SQL,但对我个人来讲,前半部分基本就够用,可以指出死锁的原因,至于后面那些有兴趣可以多研究研究。

As we already know, usually blocking happens due non-optimized queries. But how to detect queries that need to be optimized? Of course, in case of severe issues, we can analyze the queries that timeouts on the client side, but it gives us only the worst cases – with default settings it would show the queries that ran for more than 30 seconds.

现在我们已经知道阻塞是因为未经过优化的查询造成的,但是如何去探测我们有哪些语句是需要优化的呢?当然,在非常严重的情况下,我们可以分析在客户端执行超时的查询,但它只提醒在默认设置下的超时。

So, what can we do? Keeping various monitoring software out of scope, there are 2 simple methods to do the troubleshooting. First one is Blocking Process Report and second one is DMV. Let’s start with the first one.

我们能做什么呢?这里有两种解决方法:第一是Blocking process report ,第二是利用DMV。我们先看简单点的Blocking Process report。

注:我个人也比较喜欢这个,没有专业的SQL语句,提供图形化的操作界面。

Blocking process report provides you nice XML with information about sessions involved in the blocking. But first, you have to set Blocked Process Threshold with the following commands:

要查看Blocking process report呢,我们需要有一个的权限,需要拥有Sysadmin的权限,然后再设置一些系统配置。Blocking process report提供了非常友好的信息,里面包含有和阻塞相关的会话信息。


EXECUTE sp_configure 'show advanced options', 1
GO
RECONFIGURE
GO
EXECUTE sp_configure 'blocked process threshold', 5 -- in seconds.
GO
RECONFIGURE
GO
EXECUTE sp_configure 'show advanced options', 0
GO
RECONFIGURE
GO

Of course, you should think what threshold you want to use and balance between a lot or very few events reported. I’d suggest to start with threshold of 5 seconds – if you have processes that are blocked for more than 5 seconds there is the good chance that deadlock monitor is constantly running. There are 2 things to keep in mind. First – SQL does the good job trying to monitor the blocking and generate blocked processes report, but it does not guarantee that it will do it all the time. E.g. it does the check when it has available resources to do so. Secondary, if you have process blocked for a long time, SQL generates report on every try. I.e. if you have threshold equal to 5 seconds, you will get the different reports for the same blocked condition after 5 seconds, 10 seconds and so on.

After you set that threshold, the next step is to run SQL Server Profiler and setup the trace with only 1 event: “Blocked process report”. You can do it in UI:

But the better way to run server side trace. You can export trace definition and run the script to do that.

I’m not going to focus on the details how to set it up – you can find information in Books Online. So let’s see what information that trace produces. Let’s run the blocking script from my previous post. In one session let’s run the update in uncommitted transaction (X lock on the row):

In another session let’s run select that introduces table scan:

Blocked process trace generates the report with following XML.

It has 2 elements: blocked-process and blocking-process. Simple case has just 2 processes involved but in real life it could be more complicated – Process A can block Process B and same time be blocked by Process C. That leads to the multiple events in the trace.

Let’s take a quick look at the details. First of all, you can see the status (red lines). Blocked process has the status of “Suspended”. Blocking process status is more interesting. “Sleeping” status indicates that process is waiting for the next command. Most likely it’s the sign of incorrect transaction handling on the client. Think about situation when client starts transaction when user opens the form, update data when user does some changes and commit or rollback it when user clicks on SAVE or CANCEL button.

Next, blocking report shows quite a few details about processes itself (Green lines). SPID, login, host, client app, etc. It also includes the information (Blue lines) about transaction isolation level, lock mode requested as well as point to resource that is locked. If you need, you can trace it down to specific row although I found that it’s rarely needed.

But most interesting are execution stacks and buffers (Pink blocks). For Ad-hoc sql you can see actual SQL involved in the locking. The situation is a little bit more complicated when stored procedures are involved. Let’s take a look. First, let’s create the simple procedure that replaces this update statement:

Next, let’s run this SP and select statement again. Make sure you commit or rollback transaction from the previous example first. Here is the blocking report:

As you can see in the blocking report, it does not show you what statement caused the blocking. In order to get it, you can use SQLHandle from the top statement in the execution stack and sys.dm_exec_sql_text data management function. Let’s see that:

You can either count the line based on the trace value or find the actual statement based on offsets. It worth to mention that this could return different statement that the one that acquired the lock.

That method has one major drawback – statement needs to be in the cache in order at the time when you call sys.dm_exec_sql_text function. Alternative and better method to obtain blocked process report is using extended events (SQL Server 2008+). While it returns the same data, event is triggered at the time of the blocking, so you can analyze/query the system at the time of the blocking. But it’s far more complex to setup and out of the scope for now.

After you find the statements involved in the blocking, you can analyze while blocking occurs. As I mentioned before, the chance is that there are scans involved. You can use management studio and see execution plan there. Alternatively I found that those queries are quite often become one of the biggest IO consumers in the system, so you’ll see them if you analyze sys.dm_query_exec_stats data management view. You can use the script below. If query is there – just click on the plan and you’re all set.


SELECT TOP 50
SUBSTRING(qt.TEXT, (qs.statement_start_offset/2)+1,
((
CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.TEXT)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2)+1),
qp.query_plan,
qs.execution_count,
(qs.total_logical_reads + qs.total_logical_writes) / qs.execution_count as [Avg IO],
qs.total_logical_reads, qs.last_logical_reads,
qs.total_logical_writes, qs.last_logical_writes,
qs.total_worker_time,
qs.last_worker_time,
qs.total_elapsed_time/1000 total_elapsed_time_in_ms,
qs.last_elapsed_time/1000 last_elapsed_time_in_ms,
qs.last_execution_time

FROM
sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY
[Avg IO] DESC

Blocking process report is extremely useful when you need to collect information about blocking. Although, if you need to look what happens in the system right now, you can use sys.dm_tran_locks data management view. I’ll show you 2 scripts below.

The first one gives you the list of the locks system has right now:

select
TL1.resource_type
,DB_NAME(TL1.resource_database_id) as [DB Name]
,CASE TL1.resource_type
WHEN 'OBJECT' THEN OBJECT_NAME(TL1.resource_associated_entity_id, TL1.resource_database_id)
WHEN 'DATABASE' THEN 'DB'
ELSE
CASE
WHEN TL1.resource_database_id = DB_ID()
THEN
(
select OBJECT_NAME(object_id, TL1.resource_database_id)
from sys.partitions
where hobt_id = TL1.resource_associated_entity_id
)
ELSE
'(Run under DB context)'
END
END as ObjectName
,TL1.resource_description
,TL1.request_session_id
,TL1.request_mode
,TL1.request_status
,WT.wait_duration_ms as [Wait Duration (ms)]
,(
select
SUBSTRING(
S.Text,
(ER.statement_start_offset / 2) + 1,
((
CASE
ER.statement_end_offset
WHEN -1
THEN DATALENGTH(S.text)
ELSE ER.statement_end_offset
END - ER.statement_start_offset) / 2) + 1)
from
sys.dm_exec_requests ER
cross apply sys.dm_exec_sql_text(ER.sql_handle) S
where
TL1.request_session_id = ER.session_id
) as [Query]
from
sys.dm_tran_locks as TL1 left outer join sys.dm_os_waiting_tasks WT on
TL1.lock_owner_address = WT.resource_address and TL1.request_status = 'WAIT'
where
TL1.request_session_id <> @@SPID
order by
TL1.request_session_id

The second one is slightly modified version that shows you only blocking and blocked processes.


/*
Shows blocked and blocking processes. Even if it works across all database, ObjectName
populates for current database only. Could be modified with dynamic SQL if needed

Be careful with Query text for BLOCKING session. This represents currently active
request for this specific session id which could be different than query which produced locks
It also could be NULL if there are no active requests for this session
*/
select
TL1.resource_type
,DB_NAME(TL1.resource_database_id) as [DB Name]
,CASE TL1.resource_type
WHEN 'OBJECT' THEN OBJECT_NAME(TL1.resource_associated_entity_id, TL1.resource_database_id)
WHEN 'DATABASE' THEN 'DB'
ELSE
CASE
WHEN TL1.resource_database_id = DB_ID()
THEN
(
select OBJECT_NAME(object_id, TL1.resource_database_id)
from sys.partitions
where hobt_id = TL1.resource_associated_entity_id
)
ELSE
'(Run under DB context)'
END
END as ObjectName
,TL1.resource_description
,TL1.request_session_id
,TL1.request_mode
,TL1.request_status
,WT.wait_duration_ms as [Wait Duration (ms)]
,(
select
SUBSTRING(
S.Text,
(ER.statement_start_offset / 2) + 1,
((
CASE
ER.statement_end_offset
WHEN -1
THEN DATALENGTH(S.text)
ELSE ER.statement_end_offset
END - ER.statement_start_offset) / 2) + 1)
from
sys.dm_exec_requests ER
cross apply sys.dm_exec_sql_text(ER.sql_handle) S
where
TL1.request_session_id = ER.session_id
) as [Query]
from
sys.dm_tran_locks as TL1 join sys.dm_tran_locks TL2 on
TL1.resource_associated_entity_id = TL2.resource_associated_entity_id
left outer join sys.dm_os_waiting_tasks WT on
TL1.lock_owner_address = WT.resource_address and TL1.request_status = 'WAIT'

where
TL1.request_status <> TL2.request_status and
(
TL1.resource_description = TL2.resource_description OR
(TL1.resource_description is null and TL2.resource_description is null)
)

So those are 2 techniques that can help you with the troubleshooting. Again, I think it’s not as powerful as extended events approach but same time those are much simpler to accomplish.

转载于:https://www.cnblogs.com/ASPNET2008/p/3603602.html

[翻译]:SQL死锁-阻塞探测相关推荐

  1. SQL死锁知识及解决办法

    [翻译]:SQL死锁-死锁排除 min.jiang 2014-03-18 00:23 阅读:874 评论:1   项目中死锁的解决经历 min.jiang 2014-03-17 01:09 阅读:42 ...

  2. SQL Server阻塞与锁

    在讨论阻塞与加锁之前,需要先理解一些核心概念:并发性.事务.隔离级别.阻塞锁及死锁. 并发性是指多个进程在相同时间访问或者更改共享数据的能力.一般情况而言,一个系统在互不干扰的情况下可以激活的并发用户 ...

  3. [SQL]死锁处理语句

    引言 今天在群里看到分享的解决死锁的sql语句,就想着这东西以后肯定用的着,就下载下来,在这里记录一下,以后查找也方便. SQL 1 SET QUOTED_IDENTIFIER ON 2 GO 3 S ...

  4. 需要我们了解的SQL Server阻塞原因与解决方法 - sym_cn

    2019独角兽企业重金招聘Python工程师标准>>> 这里通过连接在sysprocesses里字段值的组合来分析阻塞源头,可以把阻塞分为以下5种常见的类型(见表).waittype ...

  5. SQL Server 阻塞原因分析

    这里通过连接在sysprocesses里字段值的组合来分析阻塞源头,可以把阻塞分为以下5种常见的类型(见表).waittype,open_tran,status,都是sysprocesses里的值,& ...

  6. [翻译]SQL Server 该做和不该做的

    出处:http://www.codeproject.com/cs/database/sqldodont.asp 仅供学习省事用,翻译不准,详细了解请看原文. 假设你第一次主导一个基于SQL Serve ...

  7. 锁 死锁 阻塞 Latch 等待 详解

    锁这东西是纯概念性的东西,但是作用又非常大.以前整理过两篇文章,今天又看了点书,觉得还不是很清楚.就重新整理了下.在想要不要把以前的文章删掉,这样在blog里是比较简介的,但后来又一想.这些连接在其他 ...

  8. Sql server 阻塞定位

    很多人都遇到过这样的情况,当网站达到一定的访问量,数据库就会成为瓶颈,进而引起阻塞. 有人认为这可能就是硬件的极限了,于是想办法增加硬件设备.而我本人认为问题的元凶可能是性能不高的sql脚本,引起了阻 ...

  9. Transaction中的SQL死锁

    试考察以下SQL语句: declare a_var integer; begin select col_a into a_var from tab_a where id = 1; update tab ...

最新文章

  1. Python七大原则,24种设计模式
  2. 手把手教你安装OpenStack——Ocata安装指南(上)
  3. (SpringMVC)拦截器
  4. 云南职称计算机准考证打印,会计考试准考证打印
  5. Spring中实体类为什么不需要注册成bean?
  6. 多么痛的领悟!差不多2015年的时候,我开始关注股票
  7. 基于Ruby的Watir-WebDriver自动化测试框架
  8. python的返回函数的作用_函数的返回值和作用域
  9. 人生值得珍藏的80句话
  10. ubuntu 12.04 源码安装 Xen 4.2
  11. 7-4 华氏度转摄氏度 (5分) java
  12. linux网站如何添加swf支持,linux上查看swf文件.靠谱
  13. 求和(单例模式,初始化列表,容器,迭代器)
  14. 关于随机森林randomforest对结果进行分类的原则的个人理解
  15. 负数补码表示范围以及规格化数
  16. bat 批处理拷贝文件
  17. 数据库驱动和JDBC
  18. 明日之后找回原来的服务器,明日之后怎么找回原来的账号
  19. 手机号码归属地查询 - 一刀工具
  20. qperf测试网络带宽(linux离线安装+测试教程)

热门文章

  1. jsp网页无法加载css解决方法
  2. 把英文翻译成中文php,中文翻译成英文,英文翻译成中文(调用的有道翻译的api)示例源码...
  3. 51单片机汇编学习例程(17)——KeyPad4X4篇
  4. 中国汽车用品行业需求态势及销售前景规模调研报告2021-2027年
  5. 场内基金和场外基金区别
  6. 更新chrome驱动
  7. 网站被恶意镜像怎么办 php一段代码轻松搞定(全面版)
  8. 零基础学浙大翁恺C语言(4):进一步的判断与循环
  9. 计算机网络校园局域网课题,选题表任务书(校园局域网的组建与维护).doc
  10. linux 程序加启动项,linux 让一个程序开机自启动并把一个程序加为服务