文章编号: 832524 - 最后修改: 2007年4月25日 - 修订: 1.6

SQL Server 技术公告-如何解决死锁

系统提示此文章适用于与您所使用的操作系统不同的操作系统。文章内容可能与您无关,并且已被禁用。

本页


展开全部 | 关闭全部

SQL Server 技术公告

主题介绍此问题: 如何解决死锁

目标

若要标识、 疑难解答,和建议用于解决死锁的解决方案。

简介

本文检查死锁情况下,并提供有关步骤,说明如何解决死锁。每个死锁可能不同,可能由几个不同的环境变量引起。本文中提供的信息可以帮助您识别并解决死锁。

案例研究

在一个案例分析中,我们将分析 911 具有六个运算符的系统。在活动高峰期间他们正在使用该 Microsoft Visual Basic 前端应用程序遇到已中断的连接。由于该已中断的连接的运算符必须 re-input 数据。对于 911 系统运行一天 24 小时,七天一周,这一行为是不可接受。

死锁是什么?

当两个时,会发生死锁系统服务器进程 id (spid) 正在等待一个资源,因为其他进程正在阻止它获取该资源不能处理这两个过程。

锁管理器的线程检查的死锁。锁管理器的死锁检测算法在检测到死锁时锁管理器中选择该 spid 之一为牺牲品。锁管理器将启动一个 1205年的错误消息发送到客户端,并且锁管理器删除 SPID。终止 SPID 释放资源,并允许其他 SPID 以继续。中止死锁牺牲品的 SPID 是什么导致可视化的基本前端应用程序,断开的连接。

在设计良好的应用程序前端应用程序应 1205年错误的补漏白,请重新连接到 SQL Server,然后重新提交该事务。

虽然死锁可能会最小化,但是,它们不能被完全避免。这是前端应用程序应设计为处理死锁的原因。

如何识别死锁

第 1 步

若要打算死锁,您必须首先获得日志的信息。如果您怀疑死锁,您必须收集到关于 (spid) 和死锁中涉及的资源的信息。若要执行此操作将添加-T1204 和 SQL Server-T3605 启动参数。若要将这两个启动参数,请按照下列步骤操作:
  • 启动 SQL Server 企业管理器。
  • 选择,然后再用鼠标右键单击该服务器。
  • 单击 属性
  • 单击 $ 启动参数
  • 启动参数 对话框中键入 -T1204参数 文本中框,然后再单击 添加
  • 参数 文本框中键入 -T3605,然后单击 添加
  • 单击 确定

启动参数将 SQL Server 是停止,然后重新启动时生效。

-T1204 启动参数收集有关该过程的信息和资源时死锁检测算法遇到死锁。-T3605 启动参数将此信息写入 SQL Server 错误日志。

-T1205 启动参数收集信息了死锁在遇到死锁时,不为死锁算法将检查每次。您没有使用-T1205 启动参数。

如果使用了-T1205 启动参数,以下是将 SQL Server 错误日志中的输出的示例:

2003-05-14 11:46:26.76 spid4     Starting deadlock search 1
2003-05-14 11:46:26.76 spid4     Target Resource Owner:
2003-05-14 11:46:26.76 spid4      ResType:LockOwner Stype:'OR' Mode: S SPID:55 ECID:0 Ec:(0x43CAB580) Value:0x42bdf340
2003-05-14 11:46:26.76 spid4      Node:1       ResType:LockOwner Stype:'OR' Mode: S SPID:55 ECID:0 Ec:(0x43CAB580) Value:0x42bdf340
2003-05-14 11:46:26.76 spid4     
2003-05-14 11:46:26.76 spid4     End deadlock search 1 ... a deadlock was not found.
2003-05-14 11:46:26.76 spid4     ----------------------------------
2003-05-14 11:46:31.76 spid4     ----------------------------------
2003-05-14 11:46:31.76 spid4     Starting deadlock search 2


有时,您可能不能停止并重新启动 SQL Server。在这种情况下,您可以使用查询分析器运行以下命令来启用死锁跟踪标志。

注意这种方式,您可以立即收集有关在死锁的信息。"-1"表示所有的 spid。

dbcc traceon (1204, 3605, -1)
go
dbcc tracestatus(-1)
go

第 2 步

接下来,您必须收集 SQL 事件探查器跟踪。如果您打开死锁跟踪标志,则将得到大多数所需的信息,但不是总是。例如对于在案例研究跟踪标志输出标识 sp_cursoropen 系统存储过程和一个"UPDATE tblQueuedEvents 设置 notifyid = 3,ResynchDate"死锁中涉及语句。遗憾的是,您不知道 sp_cursoropen 系统存储过程的定义。 您还没有完成 UPDATE 语句因为它已被截断。

SQL 事件探查器可以获得完整的语句,除了语句的执行计划。SQL 事件探查器跟踪还具有一个锁事件为"死锁"和"死锁链。-T1204 标志与对应的"死锁"和"死锁的链"对应于-T1205 标志。死锁跟踪标记打开和运行 SQL 事件探查器跟踪过程中出现的死锁次数应将为您提供解决死锁所必需的数据。在这种情况下和在其他,运行 SQL 事件探查器更改以避免死锁的执行到足够的时间。因此,您通常会捕获死锁信息跟踪标志,然后在运行 SQL 事件探查器。

故障排除死锁

发生死锁后,您可以通过使用 sqldiag 实用工具,以及通过使用 SQL 事件探查器来收集有关死锁的信息。在 SQLDiag.txt 文件的输出,查找"等待的图形"项。A"等待-为图形"条目指示遇到了死锁。

下面是一个示例,您可能会看到 SQL Server 错误日志中使用时将输出-T1205 启动参数。

2003-05-05 15:11:50.80 spid4    Wait-for graph
2003-05-05 15:11:50.80 spid4    Node:1
2003-05-05 15:11:50.80 spid4    ResType:LockOwner Stype:'OR' Mode: S SPID:55 ECID:0 Ec:(0x33AE1538) Value:0x193
2003-05-05 15:11:50.80 spid4    Victim Resource Owner:
2003-05-05 15:11:50.80 spid4    ResType:LockOwner Stype:'OR' Mode: X SPID:60 ECID:0 Ec:(0x1F1BB5B0) Value:0x193
2003-05-05 15:11:50.80 spid4    Requested By: 
2003-05-05 15:11:50.80 spid4    Input Buf: RPC Event: sp_cursoropen;1
2003-05-05 15:11:50.80 spid4    SPID: 55 ECID: 0 Statement Type: EXECUTE Line #: 1
2003-05-05 15:11:50.80 spid4    Owner:0x1937f2a0 Mode: S        Flg:0x0 Ref:1 Life:00000000 SPID:55 ECID:0
2003-05-05 15:11:50.80 spid4    Grant List 0::
2003-05-05 15:11:50.80 spid4    KEY: 8:1653632984:2 (da00ce043a9e) CleanCnt:1 Mode: U Fl ags: 0x0
 
2003-05-05 15:11:50.80 spid4    Node:2
2003-05-05 15:11:50.80 spid4    ResType:LockOwner Stype:'OR' Mode: S SPID:55 ECID:0 Ec:(0x33AE1538) Value:0x193
2003-05-05 15:11:50.80 spid4    Requested By: 
2003-05-05 15:11:50.80 spid4    Input Buf: Language Event: Update tblQueuedEvents Set NotifyID = 2, ResynchDate
2003-05-05 15:11:50.80 spid4    SPID: 60 ECID: 0 Statement Type: UPDATE Line #: 1
2003-05-05 15:11:50.80 spid4    Owner:0x1936e420 Mode: X        Flg:0x0 Ref:0 Life:02000000 SPID:60 ECID:0
2003-05-05 15:11:50.80 spid4    Grant List 0::
2003-05-05 15:11:50.80 spid4    KEY: 8:1653632984:1 (2d018af70d80) CleanCnt:1 Mode: X Flags: 0x0


在"等待的图形"的条目必须节点 1 和节点 2。在每个节点,您可以授予部分和请求部分。授权部分是"允许列表,"和请求部分是在"请求者"。
在每个节点中,您可以确定下列:
  • SPID。
  • 正在执行的 SPID 命令。
  • 该资源。
  • 在资源锁模式。

例如对于节点 1 授予列表中的 SPID 55 必须被授予更新锁模式: U 资源 KEY: 8:1653632984:2。8 = DBID,1653632984 = ObjectID,和 2 = Indid。若要获取数据库标识号,运行 sp_helpdb 存储过程。若要获取表,运行下面的代码:
select * from sysobjects where id = 1653632984


要获得索引,运行下面的代码:
select * from sysindexes where indid = 2 and id = 1653632984

是否等于 2 IndexId 您知道该索引是一个非聚集索引。SPID 55 正在执行的命令时 sp_cursoropen 存储过程。

节点 2 授予列表中已授予 SPID 60 的排它锁模式: X 资源 KEY: 8:1653632984:1。 8 = DBID,1653632984 = ObjectID,1 = Indid。这是在同一个表,但是 1 的索引是聚集的索引。SPID 60 正在执行的命令是:
Update tblQueuedEvents Set NotifyID = 2, ResynchDate

等于 1 的 IndexId 是聚集的索引。

等于 2 一个 IndexId 是一个非聚集索引。

注意死锁是很敏感的时间。

接下来,在节点 1 请求者 SPID 55 请求共享的锁模式: S 上 IndexId, = 1。在节点 2 中请求者、 SPID 60 请求一个独占锁模式: X 上 IndexId = 2。因为这些锁请求发生在同一时间,就会发生死锁。每个 SPID 的授予锁阻止请求的锁继续。

下表显示了锁兼容性图表。锁兼容性有关的详细信息,请参阅"锁兼容性"主题中 SQL Server 2000 丛书联机。

锁兼容性图表
收起该表格展开该表格
请求模式SUIX六个X
意向共享 (IS)
共享 (S)
更新 (U)
意向排它 (IX)
共享意向排它 (SIX)
排它 (X)


接下来,通过查看输出标识 ObjectId 1653632984 与 tblQueuedEvents 表,并获取输出表的 sp_help 存储过程。在表上没有两个索引。两个的索引是 ix_tblQueuedEvents 和 $ PK_tblQueuedEventix_tblQueuedEvents 是 ResynchDate 上的聚集的索引,PK_tblQueuedEvent 是一个主关键字 EventSID 上的唯一非聚集索引。

SQL 事件探查器跟踪未捕获死锁事件。请记住的死锁是很相关的时间。SQL 事件探查器的系统开销可能添加到的某个进程执行的一些时间和的阻止在死锁的情况下获取 SQL 事件探查器。但是,它未提供可用于解决问题的信息。找到完整更新 tblQueuedEvents 语句将类似于以下内容:

Update tblQueuedEvents Set NotifyID = 2, ResynchDate = '5/7/2003 10:44:16' where eventSID = 73023
您还会发现执行计划。您仍然不能完全 sp_cursoropen 存储过程语句中,但您有足够的信息,可以建议一个解决方案,它将解决死锁。

下面是执行计划。

注意读取此特定的执行计划从右到左和底部到顶部。

StmtText                                                      
				                                                                           
				   
				                                  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
				
Update tblQueuedEvents Set NotifyID = 2, ResynchDate = '5/7/2003 10:44:16'
				where eventSID = 73023                                                     
				   
				                    
|--Clustered Index
				Update(OBJECT:([SOTS].[dbo].[tblQueuedEvents].[ix_tblQueuedEvents ]),
				SET:([tblQueuedEvents].[NotifyID]=[@1],
				[tblQueuedEvents].[ResynchDate]=[Expr1004]))  
     |--Top(1)                                                                 
				                                                                           
				   
				               
           |--Compute Scalar(DEFINE:([Expr1004]=Convert([@2])))                
				                                                                           
				   
				                
                 |--Index
				Seek(OBJECT:([SOTS].[dbo].[tblQueuedEvents].[PK_tblQueuedEvents]),
				SEEK:([tblQueuedEvents].[EventSID]=[@3]) 

建议一个解决方案来解决死锁

请注意 UPDATE 语句的执行在聚集索引上的"聚集的索引更新"。因此,非聚集索引和聚集的索引必须同时更新。聚集的索引是 ix_tblQueuedEvents,非聚集的索引是 PK_tblQueuedEvents。若要进行更新 UPDATE 语句必须获取排它锁这两个索引。这两个索引是死锁中涉及的索引。从审阅 SQL 事件探查器跟踪,您不会看到使用该 ResynchDate WHERE 子句中的任何查询。所有语句都是非常特定并且 WHERE 子句中使用该 EventSID 它们。聚集索引的更好的选择将 EventSID。使用此信息和与客户进行讨论,我们发现 ResynchDate 索引被旧,它不需要。我们建议客户 ResynchDate,放 ix_tblQueuedEvents 索引,并且它们使得 PK_tblQueuedEvent 聚集的索引。解决此问题出现死锁情况。

这是涉及锁的死锁事例的一个示例。死锁可以还涉及并行度和涉及线程。它们可以包括一个、 两个、 三个,或多个 spid 和资源。任何的死锁情况中,您必须获取 –T1204 启动参数的输出结果和 SQL 事件探查器跟踪来标识、 诊断,和若要解决死锁。您的死锁情况将涉及不同的进程和资源。因此,解决方案将案例从而变化。您可以使用来解决死锁的典型方法是:
  • 添加和删除索引。
  • 添加索引提示。
  • 修改应用程序以访问类似的模式中的资源。
  • 删除触发器像事务中添加活动。 默认状态下,触发器是事务性的。
  • 保持事务尽可能地短。

更多阅读

有关死锁的详细信息,请访问以下 Microsoft 网站:

http://msdn2.microsoft.com/en-us/library/Aa213040 (http://msdn2.microsoft.com/en-us/library/Aa213040)

http://msdn2.microsoft.com/en-us/library/aa213042(SQL.80).aspx (http://msdn2.microsoft.com/en-us/library/aa213042(SQL.80).aspx)

http://msdn2.microsoft.com/en-us/library/aa213028(SQL.80).aspx (http://msdn2.microsoft.com/en-us/library/aa213028(SQL.80).aspx)

http://msdn2.microsoft.com/en-us/library/aa937573(SQL.80).aspx (http://msdn2.microsoft.com/en-us/library/aa937573(SQL.80).aspx)

http://msdn2.microsoft.com/en-us/library/aa213041(SQL.80).aspx (http://msdn2.microsoft.com/en-us/library/aa213041(SQL.80).aspx)

这篇文章中的信息适用于:
  • Microsoft SQL Server 2000 标准版
机器翻译机器翻译
注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。
点击这里察看该文章的英文版: 832524? (http://support.microsoft.com/kb/832524/en-us/ )
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。