SQLServer技术公告:如何解决死锁技术公告:
回到顶端目标
若要标识、疑难解答,和建议用于解决死锁的解决方案。回到顶端简介
本文检查死锁情况下,并提供有关步骤,说明如何解决死锁。每个死锁可能不同,可能由几个不同的环境变量引起。本文中提供的信息可以帮助您识别并解决死锁。回到顶端案例研究
在一个案例分析中,我们将分析911具有六个运算符的系统。在活动高峰期间他们正在使用该MicrosoftVisualBasic前端应用程序遇到已中断的连接。由于该已中断的连接的运算符必须re-input数据。对于911系统运行一天24小时,七天一周,这一行为是不可接受。回到顶端死锁是什么?
当两个时,会发生死锁系统服务器进程id(spid)正在等待一个资源,因为其他进程正在阻止它获取该资源不能处理这两个过程。
锁管理器的线程检查的死锁。锁管理器的死锁检测算法在检测到死锁时锁管理器中选择该spid之一为牺牲品。锁管理器将启动一个1205年的错误消息发送到客户端,并且锁管理器删除SPID。终止SPID释放资源,并允许其他SPID以继续。中止死锁牺牲品的SPID是什么导致可视化的基本前端应用程序,断开的连接。
在设计良好的应用程序前端应用程序应1205年错误的补漏白,请重新连接到SQLServer,然后重新提交该事务。
虽然死锁可能会最小化,但是,它们不能被完全避免。这是前端应用程序应设计为处理死锁的原因。回到顶端如何识别死锁
第1步
若要打算死锁,您必须首先获得日志的信息。如果您怀疑死锁,您必须收集到关于(spid)和死锁中涉及的资源的信息。若要执行此操作将添加-T1204和SQLServer-T3605启动参数。若要将这两个启动参数,请按照下列步骤操作:
?启动SQLServer企业管理器。?选择,然后再用鼠标右键单击该服务器。?单击属性属性。?单击$启动参数启动参数。?启动参数对话框中键入-T1204参数文本中框,然后再单击添加添加。?在参数文本框中键入-T3605,然后单击添加添加。?单击确定确定。
启动参数将SQLServer是停止,然后重新启动时生效。
-T1204启动参数收集有关该过程的信息和资源时死锁检测算法遇到死锁。-T3605启动参数将此信息写入SQLServer错误日志。
-T1205启动参数收集信息了死锁在遇到死锁时,不为死锁算法将检查每次。您没有使用-T1205启动参数。
如果使用了-T1205启动参数,以下是将SQLServer错误日志中的输出的示例:
2003-05-1411:46:26.76spid42003-05-1411:46:26.76spid4
Startingdeadlocksearch1TargetResourceOwner:
2003-05-1411:46:26.76spid4ResType:LockOwnerStype:'OR'Mode:SSPID:55ECID:0Ec:(0x43CAB580)Value:0x42bdf3402003-05-1411:46:26.76spid4Node:1ResType:LockOwnerStype:'OR'Mode:SSPID:55ECID:0Ec:(0x43CAB580)Value:0x42bdf3402003-05-1411:46:26.76spid42003-05-1411:46:26.76spid4Enddeadlocksearch1...adeadlockwasnotfound.2003-05-1411:46:26.76spid4---------------------------------2003-05-1411:46:31.76spid4---------------------------------2003-05-1411:46:31.76spid4Startingdeadlocksearch2
有时,您可能不能停止并重新启动SQLServer。在这种情况下,您可以使用查询分析器运行以下命令来启用死锁跟踪标志。
注意这种方式,您可以立即收集有关在死锁的信息。"-1"表示所有的spid。注意
dbcctraceon(1204,3605,-1)godbcctracestatus(-1)go
第2步
接下来,您必须收集SQL事件探查器跟踪。如果您打开死锁跟踪标志,则将得到大多数所需的信息,但不是总是。例如对于在案例研究跟踪标志输出标识sp_cursoropen系统存储过程和一个"UPDATEtblQueuedEvents设置notifyid=3,ResynchDate"死锁中涉及语句。遗憾的是,您不知道sp_cursoropen系统存储过程的定义。您还没有完成UPDATE语句因为它已被截断。
SQL事件探查器可以获得完整的语句,除了语句的执行计划。SQL事件探查器跟踪还具有一个锁事件为"死锁"和"死锁链。-T1204标志与对应的"死锁"和"死锁的链"对应于-T1205标志。死锁跟踪标记打开和运行SQL事件探查器跟踪过程中出现的死锁次数应将为您提供解决死锁所必需的数据。在这种情况下和在其他,运行SQL事件探查器更改以避免死锁的执行到足够的时间。因此,您通常会捕获死锁信息跟踪标志,然后在运行SQL事件探查器。回到顶端故障排除死锁
发生死锁后,您可以通过使用sqldiag实用工具,以及通过使用SQL事件探查器来收集有关死锁的信息。SQLDiag.txt文件的输出,在查找"等待的图形"项。A"等待-为图形"条目指示遇到了死锁。
下面是一个示例,您可能会看到SQLServer错误日志中使用时将输出-T1205启动参数。
2003-05-0515:11:50.80spid4
Wait-forgraph
2003-05-0515:11:50.80spid4Node:12003-05-0515:11:50.80spid4ResType:LockOwnerStype:'OR'Mode:SSPID:55ECID:0Ec:(0x33AE1538)Value:0x1932003-05-0515:11:50.80spid4VictimResourceOwner:
2003-05-0515:11:50.80spid4ResType:LockOwnerStype:'OR'Mode:XSPID:60ECID:0Ec:(0x1F1BB5B0)Value:0x1932003-05-0515:11:50.80spid42003-05-0515:11:50.80spid4sp_cursoropen;12003-05-0515:11:50.80spid4RequestedBy:InputBuf:RPCEvent:SPID:55ECID:0StatementType:
EXECUTELine#:12003-05-0515:11:50.80spid4Owner:0x1937f2a0Mode:SFlg:0x0Ref:1Life:00000000SPID:55ECID:02003-05-0515:11:50.80spid4GrantList0::2003-05-0515:11:50.80spid4KEY:8:1653632984:2(da00ce043a9e)CleanCnt:1Mode:UFlags:0x02003-05-0515:11:50.80spid4Node:2
2003-05-0515:11:50.80spid4ResType:LockOwnerStype:'OR'Mode:SSPID:55ECID:0Ec:(0x33AE1538)Value:0x1932003-05-0515:11:50.80spid4RequestedBy:2003-05-0515:11:50.80spid4InputBuf:LanguageEvent:UpdatetblQueuedEventsSetNotifyID=2,ResynchDate2003-05-0515:11:50.80spid4SPID:60ECID:0StatementType:UPDATELine#:12003-05-0515:11:50.80spid4Owner:0x1936e420Mode:XFlg:0x0Ref:0Life:02000000SPID:60ECID:02003-05-0515:11:50.80spid4GrantList0::2003-05-0515:11:50.80spid4KEY:8:1653632984:1(2d018af70d80)CleanCnt:1Mode:XFlags:0x0
在"等待的图形"的条目必须节点1和节点2。在每个节点,您可以授予部分和请求部分。授权部分是"允许列表,"和请求部分是在"请求者"。在每个节点中,您可以确定下列:
?SPID。?正在执行的SPID命令。?该资源。?在资源锁模式。
例如对于节点1授予列表中的SPID55必须被授予更新锁模式:U资源KEY:
8:1653632984:2。8=DBID,1653632984=ObjectID,和2=Indid。若要获取数据库标识号,运行sp_helpdb存储过程。若要获取表,运行下面的代码:
select*fromsysobjectswhereid=1653632984
要获得索引,运行下面的代码:
select*fromsysindexeswhereindid=2andid=1653632984
是否等于2IndexId您知道该索引是一个非聚集索引。SPID55正在执行的命令时sp_cursoropen存储过程。
节点2授予列表中已授予SPID60的排它锁模式:X资源KEY:8:1653632984:1。8=DBID,1653632984=ObjectID,1=Indid。这是在同一个表,但是1的索引是聚集的索引。SPID60正在执行的命令是:
UpdatetblQueuedEventsSetNotifyID=2,ResynchDate
等于1的IndexId是聚集的索引。
等于2一个IndexId是一个非聚集索引。
注意死锁是很敏感的时间。注意
接下来,在节点1请求者SPID55请求共享的锁模式:S上IndexId,=1。在节点2中请求者、SPID60请求一个独占锁模式:X上IndexId=2。因为这些锁请求发生在同一时间,就会发生死锁。每个SPID的授予锁阻止请求的锁继续。
下表显示了锁兼容性图表。锁兼容性有关的详细信息,请参阅"锁兼容性"主题中SQLServer2000丛书联机。
锁兼容性图表
请求模式意向共享(IS)共享(S)更新(U)意向排它(IX)
是是是是是
S是是是否
U是是否否
IX是否否是
六个是否否否
X否否否否
共享意向排它(SIX)是排它(X)否
否否
否否
否否
否否
否否
接下来,通过查看输出标识ObjectId1653632984与tblQueuedEvents表,并获取输出表的sp_help存储过程。在表上没有两个索引。两个的索引是ix_tblQueuedEvents和$PK_tblQueuedEvent。ix_tblQueuedEvents是ResynchDate上的聚集的索引,PK_tblQueuedEvent是一个主关键字EventSID上的唯一非聚集索引。
SQL事件探查器跟踪未捕获死锁事件。请记住的死锁是很相关的时间。SQL事件探查器的系统开销可能添加到的某个进程执行的一些时间和的阻止在死锁的情况下获取SQL事件探查器。但是,它未提供可用于解决问题的信息。找到完整更新tblQueuedEvents语句将类似于以下内容:
UpdatetblQueuedEventsSetNotifyID=2,ResynchDate='5/7/200310:44:16'whereeventSID=73023
您还会发现执行计划。您仍然不能完全sp_cursoropen存储过程语句中,但您有足够的信息,可以建议一个解决方案,它将解决死锁。
下面是执行计划。
注意读取此特定的执行计划从右到左和底部到顶部。注意
StmtText
-----------------------------------------------------------------------------------------------------------------------------------------------------------------UpdatetblQueuedEventsSetNotifyID=2,ResynchDate='5/7/200310:44:16'whereeventSID=73023
|--ClusteredIndex
Update(OBJECT:([SOTS].[dbo].[tblQueuedEvents].[ix_tblQueuedEvents]),SET:([tblQueuedEvents].[NotifyID]=[@1],[tblQueuedEvents].[ResynchDate]=[Expr1004]))|--Top(1)
|--ComputeScalar(DEFINE:([Expr1004]=Convert([@2])))
|--IndexSeek(OBJECT:([SOTS].[dbo].[tblQueuedEvents].[PK_tblQueuedEvents]),SEEK:([tblQueuedEvents].[EventSID]=[@3])
回到顶端建议一个解决方案来解决死锁
请注意UPDATE语句的执行在聚集索引上的"聚集的索引更新"。因此,非聚集索引和聚集的索引必须同时更新。聚集的索引是ix_tblQueuedEvents,非聚集的索引是PK_tblQueuedEvents。若要进行更新UPDATE语句必须获取排它锁这两个索引。这两个索引是死锁中涉及的索引。从审阅SQL事件探查器跟踪,您不会看到使用该ResynchDateWHERE子句中的任何查询。所有语句都是非常特定并且WHERE子句中使用该EventSID它们。聚集索引的更好的选择将EventSID。使用此信息和与客户进行讨论,我们发现ResynchDate索引被旧,它不需要。我们建议客户ResynchDate,放ix_tblQueuedEvents索引,并且它们使得PK_tblQueuedEvent聚集的索引。解决此问题出现死锁情况。
这是涉及锁的死锁事例的一个示例。死锁可以还涉及并行度和涉及线程。它们可以包括一个、两个、三个,或多个spid和资源。任何的死锁情况中,您必须获取–T1204启动参数的输出结果和SQL事件探查器跟踪来标识、诊断,和若要解决死锁。您的死锁情况将涉及不同的进程和资源。因此,解决方案将案例从而变化。您可以使用来解决死锁的典型方法是:
?添加和删除索引。?添加索引提示。?修改应用程序以访问类似的模式中的资源。?删除触发器像事务中添加活动。默认状态下,触发器是事务性的。?保持事务尽可能地短。