UPDATE 上的 SQL Server 死锁
Posted
技术标签:
【中文标题】UPDATE 上的 SQL Server 死锁【英文标题】:SQL Server Deadlock on UPDATE 【发布时间】:2012-07-20 12:57:11 【问题描述】:我的应用程序出现死锁问题。 数据库是 SQL Server 2005,当 2 个线程尝试更新同一个表时会发生死锁。 我不明白这种情况,我希望有人能帮助我。 这是死锁图:
<deadlock-list>
<deadlock victim="process3a0ac58">
<process-list>
<process id="process3a0ac58" taskpriority="0" logused="5048" waitresource="KEY: 9:72057594078035968 (e100ae2e5d7f)" waittime="4750" ownerId="22329947" transactionname="user_transaction" lasttranstarted="2012-07-20T08:53:33.440" XDES="0x24b429210" lockMode="U" schedulerid="1" kpid="1428" status="suspended" spid="57" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2012-07-20T08:53:34.753" lastbatchcompleted="2012-07-20T08:53:34.753" clientapp=".Net SqlClient Data Provider" hostname="VMDBSRVCRISPI" hostpid="4012" loginname="sa" isolationlevel="read uncommitted (1)" xactid="22329947" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="34" sqlhandle="0x0200000008adf4202a2e77131e147fe8c50b173a5f8d5302"> UPDATE [FreeAvailability] SET Resource_id = null WHERE Resource_id = @p0 AND Id = @p1 </frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000"> unknown </frame>
</executionStack>
<inputbuf> (@p0 int,@p1 int)UPDATE [FreeAvailability] SET Resource_id = null WHERE Resource_id = @p0 AND Id = @p1 </inputbuf>
</process>
<process id="process3a28da8" taskpriority="0" logused="8720" waitresource="KEY: 9:72057594078035968 (d0006ab1ca37)" waittime="2734" ownerId="22329913" transactionname="user_transaction" lasttranstarted="2012-07-20T08:53:33.067" XDES="0x28dd4aa40" lockMode="U" schedulerid="4" kpid="3732" status="suspended" spid="58" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2012-07-20T08:53:36.770" lastbatchcompleted="2012-07-20T08:53:36.737" clientapp=".Net SqlClient Data Provider" hostname="VMDBSRVCRISPI" hostpid="4012" loginname="sa" isolationlevel="read uncommitted (1)" xactid="22329913" currentdb="9" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="34" sqlhandle="0x0200000008adf4202a2e77131e147fe8c50b173a5f8d5302"> UPDATE [FreeAvailability] SET Resource_id = null WHERE Resource_id = @p0 AND Id = @p1 </frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000"> unknown </frame>
</executionStack>
<inputbuf> (@p0 int,@p1 int)UPDATE [FreeAvailability] SET Resource_id = null WHERE Resource_id = @p0 AND Id = @p1 </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594078035968" dbid="9" objectname="SDN.Napoli.dbo.FreeAvailability" indexname="PK__FreeAvailability__3939548A" id="lock4bdb180" mode="X" associatedObjectId="72057594078035968">
<owner-list>
<owner id="process3a28da8" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process3a0ac58" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594078035968" dbid="9" objectname="SDN.Napoli.dbo.FreeAvailability" indexname="PK__FreeAvailability__3939548A" id="lock4c25680" mode="X" associatedObjectId="72057594078035968">
<owner-list>
<owner id="process3a0ac58" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process3a28da8" mode="U" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
似乎在主键上发生了死锁,但这是怎么可能的,我该如何解决这个问题?
提前致谢
编辑:
这是表结构:
CREATE TABLE [dbo].[FreeAvailability](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Date] [datetime] NULL,
[StartTime] [datetime] NULL,
[EndTime] [datetime] NULL,
[BookOnlyIfRequired] [bit] NULL,
[Free48HsBefore] [bit] NULL,
[Private] [bit] NULL,
[F48HBGroup] [bit] NULL,
[Resource_id] [int] NULL,
[Sedi_id] [int] NULL,
[Skill_id] [int] NULL,
[BOIRGroup_id] [int] NULL,
[Private48HBGroup] [bit] NULL,
[Free24HsBefore] [bit] NULL,
[Free72HsBefore] [bit] NULL,
[F24HBGroup] [bit] NULL,
[F72HBGroup] [bit] NULL,
[Private24HBGroup] [bit] NULL,
[Private72HBGroup] [bit] NULL,
PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[FreeAvailability] WITH CHECK ADD CONSTRAINT [FK4D396931200F9F6C] FOREIGN KEY([Skill_id])
REFERENCES [dbo].[Skill] ([Id])
GO
ALTER TABLE [dbo].[FreeAvailability] CHECK CONSTRAINT [FK4D396931200F9F6C]
GO
ALTER TABLE [dbo].[FreeAvailability] WITH CHECK ADD CONSTRAINT [FK4D3969313F693A26] FOREIGN KEY([BOIRGroup_id])
REFERENCES [dbo].[BOIRGroup] ([Id])
GO
ALTER TABLE [dbo].[FreeAvailability] CHECK CONSTRAINT [FK4D3969313F693A26]
GO
ALTER TABLE [dbo].[FreeAvailability] WITH CHECK ADD CONSTRAINT [FK4D396931C92BB494] FOREIGN KEY([Resource_id])
REFERENCES [dbo].[Resource] ([Id])
GO
ALTER TABLE [dbo].[FreeAvailability] CHECK CONSTRAINT [FK4D396931C92BB494]
GO
ALTER TABLE [dbo].[FreeAvailability] WITH CHECK ADD CONSTRAINT [FK556546F95E61B626] FOREIGN KEY([BOIRGroup_id])
REFERENCES [dbo].[BOIRGroup] ([Id])
GO
ALTER TABLE [dbo].[FreeAvailability] CHECK CONSTRAINT [FK556546F95E61B626]
GO
ALTER TABLE [dbo].[FreeAvailability] WITH CHECK ADD CONSTRAINT [FK556546F95ECA95DC] FOREIGN KEY([Skill_id])
REFERENCES [dbo].[Skill] ([Id])
GO
ALTER TABLE [dbo].[FreeAvailability] CHECK CONSTRAINT [FK556546F95ECA95DC]
GO
ALTER TABLE [dbo].[FreeAvailability] WITH CHECK ADD CONSTRAINT [FK556546F9E6E3AAC4] FOREIGN KEY([Resource_id])
REFERENCES [dbo].[Resource] ([Id])
GO
ALTER TABLE [dbo].[FreeAvailability] CHECK CONSTRAINT [FK556546F9E6E3AAC4]
我不能说 2 个线程传递的值,因为我没有记录 :(
【问题讨论】:
请向我们展示您的表结构!您有哪些列(及其数据类型)?你在那张桌子上有什么样的索引?您的两个线程更新了Resource_Id
和ID
的哪些值?
这将是一个很好的起点sqlindian.com/2012/07/06/…
这些更新是另一个事务的一部分吗?意味着在更新开始之前你是否对同一张表上的某些行保持某种锁定?另外,你有什么样的非聚集索引桌子?
【参考方案1】:
要识别此死锁中涉及的行,请运行查询
SELECT id, %%lockres%% as LockResource FROM dbo.FreeAvailability WHERE %%lockres%% IN('(e100ae2e5d7f)','(d0006ab1ca37)')
在这个死锁中,进程 process3a0ac58 在对应于资源 (e100ae2e5d7f) 的行上持有 X 锁,并在对应于资源 (d0006ab1ca37) 的行上等待 U 锁(用于 UPDATE 的读取阶段)。
同时进程 process3a28da8 在对应于资源 (d0006ab1ca37) 的行上持有 X 锁并等待 (e100ae2e5d7f) 上的 U 锁。
死锁跟踪不会告诉您哪些语句获得了锁。我的猜测是您在同一个事务中执行多个更新。同样在这种情况下,更新以相反的顺序执行。
两个使用键级锁的独立 UPDATE 语句(由于 PK 上的 WHERE 子句)不会相互死锁。所以这应该是典型的循环死锁案例。
【讨论】:
以上是关于UPDATE 上的 SQL Server 死锁的主要内容,如果未能解决你的问题,请参考以下文章
试图防止这种死锁发生在我在 SQL Server 上的 .NET 代码中
SQL Server Profiler 中的死锁图显示同一集群键上的互锁