当数据库引擎内部的两个或多个会话等待访问彼此持有的锁定资源时,可能会发生死mysql数据库同步 锁。 从技术上讲,死锁可以看作是一个循环锁链,因为阻塞链中的每个进程(SPID)都将等待同一个阻塞链中的一个或多个其他进程,因此没有一个进程能够完成。

一旦例如,在检测到死锁,它将通过杀死一个死锁进程并回滚它正在运行的任何事务来解决它;这可能是一个重要的业务事务,需要检查错误代码中的死锁并做出相应的响应。 此外,当主角进程死锁时,其他进程也可能被阻止访问受影响的表。

本文将讨论为什么会出现死锁,为什么需要数据库管理员立即进行调查,以及排除死锁所需的诊断数据。 然后,它演示了在SQL Monitor中检测到的死锁事件,并显示了我们如何使用警报详细信息中提供的扩展事件死锁图快速找到原因,以及关于资源使用情况和警报期间执行的查询和进程的支持诊断数据。

SQL Server有一个锁监视器,它通过定期检查任何循环锁链的存在来自动检测死锁。

例如,假设会话A持有一个资源的锁,但是在会话B释放它需要访问的资源的锁之前不能继续,会话B在会话C释放锁之前不能继续,会话C在会话A释放锁之前不能继续。

SQL Server将通过终止其中一个会话(死锁牺牲品)并回滚其事务来解决死锁,从而释放其持有的所有锁。 这允许阻塞链中的其他会话继续执行。

不幸的死锁牺牲品收到了可怕的1205错误消息:

Transaction (Process ID XX) was deadlocked on resources with another process and has been chosen as the deadlock victim. 事务(进程标识XX)在资源上与另一个进程死锁,并被选为死锁牺牲品。

重新运行事务。 数据库管理员需要确保正确处理这个1205异常,以避免 UnhandledException 应用程序中的错误。

无论这是使用正在执行的SQL中的块还是应用程序代码中的块来完成的,最常见的方法是暂停事务,然后重试该事务一定次数。 仅仅因为数据库管理员不需要手动干预来解决死锁,并不意味着他们可以忽略它们。

这是一个重要的错误情况,他们应该立即进行调查,找出导致死锁的原因,并采取措施防止死锁再次发生。 首先,死锁牺牲品可能是一个重要的业务流程。 如果一个会话正在运行一个重要的进程,我们可以通过为该会话分配一个。 但是,如果死锁中涉及的两个或多个会话具有相同的死锁优先级,则选择死锁牺牲品的唯一标准是回滚会话的估计成本。

在此基础上,如果一个会话用一个已经运行了五个小时的复杂报告查询修改了单行数据死锁,那么后者将被选为受害者。 其次,死锁的一些最常见原因包括糟糕的数据库设计、缺乏索引、设计不佳的查询, 通常,原因是 (不必要或过长的显式事务)以及事务隔离级别的不当选择。 如果这些问题困扰着您的数据库,那么您的应用程序很可能不仅会出现死锁,还会出现运行缓慢的查询、严重的阻塞以及其他性能问题。

通过监控和诊断死锁,我们可以继续提高数据库的整体性能。

诊断数据的关键部分是死锁图,它向我们显示死锁涉及哪些进程和资源,哪个被选为死锁牺牲品,等等。 捕获该图的一种方法是设置服务器端探查器跟踪来捕获死锁图事件,并等待死锁再次出现。 但是,更方便的方法是使用由事件会话自动捕获的扩展事件,默认情况下,该事件会话在所有安装的SQL Server 2008及更高版本上运行。 此事件的字段保存死锁图形。

此外,唯一的是,扩展事件死锁图允许诊断多受害者死锁,其中SQL Server必须杀死多个会话来解决死锁情况。

如果您试图解决在2008年之前的实例上的死锁问题,或者由于其他原因无法使用扩展事件或事件探查器跟踪,那么我将向您推荐乔纳森·凯亚斯的文章“处理SQL Server中的死锁”中的其他方法。he target of the default event session. You can download the ReaderWriter另一种方法是切换到 code file to reproduce the deadlock.

用sql监控和排除死锁故障
Figure 1: Capturing the deadlock graph using Extended Events.

图1显示了一个扩展事件事件 你可以点击 xml报表(_ r) 打开完整的XML死锁图,如图2所示。

用sql监控和排除死锁故障
我已经手动添加了彩色框来突出死锁图的三个主要部分:受害者列表、进程列表和资源列表。

图XML死锁图。

阅读一个XML死锁图需要耐心,并且一些元素,特别是元素,包含许多字段,所以你会发现你自己向左和向右滚动以找到一些重要的细节,例如为每个死锁进程请求的隔离级别。 但是,一旦您掌握了基础知识,诊断死锁条件所需的所有信息都在那里。 Deadlock 僵局

用sql监控和排除死锁故障
选项卡查看图形的基本视觉表示。

图3:死锁图形的可视化表示是SSMS。 蓝十字清楚地表明哪个进程(SPID 84)是僵局的受害者。 单击它会弹出一个工具提示,显示它发出的最后一个SQL批处理:存储过程执行。 我们可以看到,为了执行这个批处理,进程84对一个对象发出了一个意图共享(is)锁的请求,尽管哪个对象不是立即显而易见的(它的),但是被阻止了。

我们还可以看到,进程84已经在表中的一页上拥有了一个IX锁。 另一个进程(SPID 82)已经拥有一个独占(X)锁,这是84在信息系统锁中请求的对象,这就是为什么84的请求被阻止。 我们还可以看到,进程82在一个页面上请求了一个S锁来读取它,但是被阻止了,因为进程84在其上持有一个IX锁。

因此,我们可以对这里发生的事情以及所涉及的流程和资源有所了解,但所有细节都难以捉摸。

一般来说,没有多少开发人员或数据库管理员觉得SSMS对死锁图形的可视化描述容易阅读和理解,所以大多数人坚持费力地浏览XML版本。 SQL Monitor的主要操作模式是根据任何受监控的服务器、实例和数据库上的异常或不良条件和属性或错误发出警报。

它为特定的SQL Server错误和问题(包括死锁)提供了一系列警报。 SQL Monitor 8包含一个名为死锁(扩展事件)的内置警报,默认情况下,每当死锁发生时,它都会发出中等严重性警报,并捕获扩展事件死锁图。

这意味着您可以通过SQL Monitor获得与从扩展事件获得的相同的XML死锁图,但是有一些有用的增强和优点。 首先,SQL Monitor提供了一个更简单、更清晰的死锁图形版本,它包含了诊断问题所需的所有重要信息。

其次,它提供了所有重要的上下文数据,您需要了解死锁发生时服务器和受影响数据库上的活动。

有了所有这些诊断数据,您就可以全面了解死锁发生的原因和时间,以及其他哪些流程可能会受到影响,并且可以制定消除问题的最佳策略。

用sql监控和排除死锁故障
在SQL监视器中,我们可以立即看到在我们的一个SQL Server实例上引发了死锁警报。

图4:引发了死锁警报。 对于任何警报,单击死锁警报会将我们带到 细节 选项卡 警报 屏幕。 对于每个警报,顶部的 警报

屏幕(未显示)将显示警报发出(和结束,如果相关)的时间和警报的状态。 在身体里 细节 选项卡,我们可以看到特定于警报的详细信息。

用sql监控和排除死锁故障
在这种情况下,我们看到死锁图的图形描述,如图5所示。 图5: 细节

显示图形死锁图形的死锁警报的选项卡。 扩展事件XML死锁图的来源仍然完全可用;只需点击 输出 选项卡来查看它。

但是,在SQL Monitor中,图形版本使查看所有关键细节变得非常容易。 我们可以直接看到进程84和82陷入了死锁,红色边框表示SQL Server选择了进程84作为死锁牺牲品,并将其回滚。

对于每个进程,我们可以看到发出SQL批处理的客户机的机器、应用程序和登录名。 进程84需要在表上获取一个锁来读取它,但是被阻塞了,因为进程82在这个对象上持有一个X锁。 反过来,进程82需要获取表中某页的锁来读取它,但由于进程84在该页上持有一个第九锁而被阻止。

此时,SQL Server的锁监视器检测到一个循环锁链,并以最低的回滚成本终止正在运行该进程的挂起线程。 如果我们单击其中一个进程,我们将进一步了解重要的诊断细节,包括该进程发出的SQL批处理的文本。

用sql监控和排除死锁故障
在图6中,我们看到流程82发布了一个批处理来执行一个名为的存储过程,并且执行的最后一条SQL语句是对表的查询。

图6:死锁中涉及的每个进程的细节。

同样,如果我们检查死锁牺牲品,我们将看到它正在执行一个存储过程,并且它发出的最后一条SQL语句是对表的查询。 我们还看到了SQL Server会话的事务隔离级别,在本例中,这是默认级别。

但是,值得了解的是,应用程序是否指定使用更严格的事务隔离级别(如或),这迫使SQL Server锁定资源的时间更长,并且是阻塞和死锁问题的常见原因。

使用像SQL Monitor这样的工具的优点是,我们不仅可以看到死锁数据,还可以在警报发生时SQL Server实例上发生的活动的完整上下文中看到它。

警报的服务器级和数据库级诊断数据 向下滚动 警报 屏幕上,您将看到按选项卡排列的大量性能数据,这些数据显示了发出警报时主机和SQL Server实例上的资源使用情况和活动级别的快照和摘要,以及SQL Server查询和进程或其他服务器级进程的详细信息。 SQL Server SQL服务器

用sql监控和排除死锁故障
选项卡显示了事件发生前后平均锁等待时间指标的峰值。

图7:警报发生时的SQL Server实例级度量。 顶级查询 选项卡,我们可以看到在发出警报时正在执行的查询。 默认情况下,SQL Monitor按持续时间的顺序列出它们,但是通过单击所需的列(例如逻辑读取

用sql监控和排除死锁故障
),我们可以按该列对结果重新排序。

图8:死锁警报时的顶级查询。 我们认为其中一些查询是死锁中涉及的存储过程的一部分。 如果我们单击上的查询,我们会看到查询的文本、从计划缓存中查看其查询计划的链接,以及与查询相关联的任何重要等待的列表。

用sql监控和排除死锁故障
在这种情况下,我们可以看到它在试图获取共享读锁时被迫等待。

图9:一个顶级查询的细节。 图10显示了相关的查询计划。 这个查询是存储过程的一部分(由SPID 82执行),我们可以看到存储过程中每个语句的计划。在这种情况下,存储过程(纯粹是为了演示而编写的!

用sql监控和排除死锁故障
)启动显式事务,更新表,然后查询表(回滚之前)。

图10:为导致死锁而执行的一个存储过程的查询计划。

如果我们检查图9列表中的第六个查询,我们会看到它是来自存储过程(由死锁牺牲品SPID 84执行)的查询,它以相反的顺序访问相同的表,首先更新表,然后查询表。 我们还可以看到可能受事件影响的其他流程和查询的详细信息。

用sql监控和排除死锁故障
在这种情况下,列表中运行时间最长的查询是一个单独的即席查询,它也需要访问和表,并且由于死锁的发生而遭受锁定等待。

图11:其他受影响的查询。

互动事件时间表 除了警报的特定诊断数据之外,查看受影响的SQL Server实例的概览图也非常有用,该图显示了选定时间段内的CPU、内存、输入/输出和等待,以及显示警报发生情况的“事件时间表”。 在这种情况下,我们看到一组警报,包括我们调查的死锁警报。

用sql监控和排除死锁故障
我们可以看到,在此期间,等待时间会“激增”,并且磁盘输入输出活动会达到一个显著的峰值。

图12:交互式概览图和事件时间线。 向下滚动 概述

用sql监控和排除死锁故障
页面中,我们可以看到在设定时间段内发生的顶级查询和等待,以及服务器级和数据库级指标的快照,以及在发出警报时运行的进程的特定摘要,如阻塞进程(按时间排列的前10个)等。

图13:阻塞过程(按时间排列的前10名)。 有了死锁中涉及的查询的知识和服务器上并发活动的更广泛的知识,我们就可以采取措施来解决问题,以确保问题不再发生。 这可能涉及查询调优、添加新索引、修改现有索引或其他一些缓解死锁的标准。 是一个transactionitis

,开发人员有不必要的事务,将它们保持打开太长时间,或者在事务中放置不需要的语句。 尽管本文中的死锁是出于演示目的而设计和简化的,但它是一个读取器-写入器死锁的例子,由两个进程导致,每个进程在一个显式事务中以不同的顺序更新并查询相同的两个表。

  • 在解决此问题时要问的问题包括: transactionitistransactionitis ?
  • 换句话说,假设在这两种情况下,存储过程都不包含需要形成原子单元的多个数据修改语句,那么显式事务是必要的吗?
  • 我们可以将任何一条语句移到事务之外吗?

我们能颠倒两组陈述中的一组或两组的顺序吗?

如果这些改变中的任何一个是可能的,死锁将被防止,尽管列表上的第三个解决方案依赖于使用默认的读提交隔离级别,其中共享锁在查询结束之前被释放。

有关编码技术以帮助避免死锁的更一般的建议,请参见Redgate文档中的“减少死锁”一文(参考下文)。

有了SQL Monitor,当死锁发生时,您将得到警告,让您有机会恢复任何丢失的进程,并将过程放在适当的位置,以便将来最大限度地减少死锁的发生。 SQL Monitor 8支持扩展事件死锁图,并增加了比SSMS更简单、更清晰的可视化。

  • 借助警报发出时的历史数据快照的额外好处,您可以开始全面了解发生了什么以及结果受到了什么影响。
  • 例如,盖尔·肖的一篇简单的谈话文章
  • 处理SQL Server中的死锁,乔纳森·凯亚斯的简单对话文章
  • 减少死锁,Redgate文档

相关文章: