【发布时间】:2021-04-23 16:58:30
【问题描述】:
我试图了解由 2 个存储过程导致的死锁,它们试图查询/更新 Accounts 表中的相同对象。通常,我通过涉及的 2 个不同进程在 2 个不同的关联对象上看到 2 个键锁。但是在这种情况下,两个键锁都指向相同的关联对象,这令人困惑。请问我可以得到一些帮助来理解这一点吗?
注意:存储过程在具有可序列化隔离级别的事务中执行。
<deadlock>
<victim-list>
<victimProcess id="process_victim" />
</victim-list>
<process-list>
<process id="process_victim" taskpriority="0" logused="6132" waitresource="KEY: 39:72057594582597632 (781c957ed006)" waittime="3279" ownerId="9627380307" transactionname="user_transaction" lasttranstarted="2021-01-14T15:47:08.737" XDES="0x30091b48428" lockMode="U" schedulerid="16" kpid="224656" status="suspended" spid="665" sbid="2" ecid="0" priority="0" trancount="1" lastbatchstarted="2021-01-14T15:47:08.770" lastbatchcompleted="2021-01-14T15:47:08.753" lastattention="1900-01-01T00:00:00.753" clientapp="accounts" hostname="2000000" hostpid="13528" loginname="dbUser" isolationlevel="serializable (4)" xactid="9627380307" currentdb="39" currentdbname="Trans" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="5716a4fb-ea5f-48ff-bc69-a20036b656f3.dbo.uspInsertMasterAccountTrans" queryhash="0x16139b535590589a" queryplanhash="0x30448d54aa8b7e4c" line="39" stmtstart="2412" stmtend="2708" sqlhandle="0x030027001088596482b8e700aeac000001000000000000000000000000000000000000000000000000000000">
SELECT @currentAccountBalance = [ACC].Balance
FROM [dbo].[Accounts] [ACC]
WITH (UPDLOCK, ROWLOCK, HOLDLOCK)
WHERE [ACC].AccountId = @accountId </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 39 Object Id = 1683589136] </inputbuf>
</process>
<process id="process_other" taskpriority="0" logused="9536" waitresource="KEY: 39:72057594582597632 (ef38eb644a4b)" waittime="3264" ownerId="9627380654" transactionname="user_transaction" lasttranstarted="2021-01-14T15:47:08.757" XDES="0x30089c80428" lockMode="X" schedulerid="15" kpid="216124" status="suspended" spid="532" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2021-01-14T15:47:08.783" lastbatchcompleted="2021-01-14T15:47:08.780" lastattention="1900-01-01T00:00:00.780" clientapp="accounts" hostname="1000001" hostpid="24452" loginname="dbUser" isolationlevel="serializable (4)" xactid="9627380654" currentdb="39" currentdbname="Trans" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="5716a4fb-ea5f-48ff-bc69-a20036b656f3.dbo.uspInsertDebitCashTrans" queryhash="0xe4a5aeeea80cb67b" queryplanhash="0xcbcba51d221c9bc6" line="130" stmtstart="8450" stmtend="8956" sqlhandle="0x03002700bbf435679fb8e700aeac000001000000000000000000000000000000000000000000000000000000">
UPDATE [dbo].[Accounts]
WITH (UPDLOCK, ROWLOCK, HOLDLOCK)
SET Balance = Balance - @totalPaymentAmount, TimestampModified = GETUTCDATE()
WHERE [ACC].AccountId = @debtorAccountId </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 39 Object Id = 1731589307] </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594582597632" dbid="39" objectname="5716a4fb-ea5f-48ff-bc69-a20036b656f3.dbo.Accounts" indexname="PK_dbo.Accounts" id="lock28450c72100" mode="X" associatedObjectId="72057594582597632">
<owner-list>
<owner id="process_other" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process_victim" mode="U" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594582597632" dbid="39" objectname="5716a4fb-ea5f-48ff-bc69-a20036b656f3.dbo.Accounts" indexname="PK_dbo.Accounts" id="lock28ea0da7d00" mode="X" associatedObjectId="72057594582597632">
<owner-list>
<owner id="process_victim" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process_other" mode="X" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
【问题讨论】:
-
不要“缩写”给我们完整的代码,否则无法诊断死锁。您的
SELECT不知何故占用了 X 锁,所以在事务的后面一定还有一个UPDATE -
您是否有索引以便通过搜索获取相关记录?你的
where子句是什么样的?当您从update查询中删除提示(无论如何都不需要)时会发生什么? -
@Charlieface 添加了完整的查询,实际上它并不复杂。是的,我们需要 X 锁以便稍后在同一个存储过程中进行更新,并避免任何其他并行执行的更新。
-
显示存储过程的完整代码。还为您的表和索引提供 DDL
-
@GSerg 是的,正确的索引已经到位。请注意,这是涉及 2 个不同的存储过程。我们需要更新查询中的提示,它位于 uspInsertDebitCashTrans 中,因为其中没有 SELECT before update 语句。
标签: sql sql-server deadlock database-deadlocks