【发布时间】:2019-12-12 06:59:00
【问题描述】:
我有一个 SQL Server 2016 数据库,我们一直使用 Hibernate Java (ORM) 作为前端来访问数据库。
以下情况导致死锁:其中一个事务正在执行涉及连接中的许多表的选择操作,如下所示:
select *
from table 1
inner join table2_ on table1PK = table2FK
left outer join table3 on table1PK = table3FK
left outer join table4_ on table4FK = table3PK
...
where Table1PK = '1234' and table3.Status <> 'NA'
另一个事务正在上述连接中涉及的任何表上执行UPDATE
Update Table4
set columnA = 'XYZ'
where Table4PK = 'ABC'
这两个事务之间经常出现死锁。
以下是收集到的分析:
-
Select语句连接中涉及的所有表都在 PK FK 关系上 - 所有 PK 和 FK 列都有索引(PK 集群和 FK 非集群)
- 由于查询是从 ORM Hibernate 生成的,因此它会检索
Select语句中的所有列 - 执行计划执行非聚集索引查找,然后执行所有表的键查找
- Select 语句使用 Shared S 锁,Update 语句使用 Exclusive X 锁
- 以上表格禁用页级锁
- 统计数据和索引是最新的/经常更新
由于应用程序逻辑,无法使用 READ Committed Snapshot 和 Read Uncommitted 隔离级别。
任何避免上述场景死锁的建议。
死锁跟踪:
<deadlock>
<victim-list>
<victimProcess id="process2ba81fa8c8" />
</victim-list>
<process-list>
<process id="process2ba81fa8c8" taskpriority="0" logused="0"
waitresource="KEY: 7:72057597045899264 (5a800aed3519)" waittime="2537" ownerId="1798795" transactionname="SELECT" lasttranstarted="2019-12-12T13:17:02.820" XDES="0x2841883a40" lockMode="S" schedulerid="6" kpid="10140" status="suspended" spid="429" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2019-12-12T13:17:02.823" lastbatchcompleted="2019-12-12T13:17:02.820" lastattention="1900-01-01T00:00:00.820" clientapp="Microsoft JDBC Driver for SQL Server" hostname="" hostpid="0" loginname="" isolationlevel="read committed (2)" xactid="1798795" currentdb="" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="24" stmtend="33928" sqlhandle="0x02000000a700b227b6df842918a30ca7f4b4cd5ff967f9810000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(@P0 bigint)select ... from ABC inner join XYZ </inputbuf>
</process>
<process id="process2ba81f8108" taskpriority="0" logused="5812788" waitresource="KEY: 7:72057596983508992 (c750150781e8)" waittime="2306" ownerId="1795488" transactionname="implicit_transaction" lasttranstarted="2019-12-12T13:17:02.180" XDES="0x2bb290d478" lockMode="X" schedulerid="5" kpid="9876" status="suspended" spid="382" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-12-12T13:17:03.053" lastbatchcompleted="2019-12-12T13:17:03.053" lastattention="1900-01-01T00:00:00.053" clientapp="Microsoft JDBC Driver for SQL Server" hostname="" hostpid="0" loginname="" isolationlevel="read committed (2)" xactid="1795488" currentdb="" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="1462" stmtend="3664" sqlhandle="0x020000007bd3bd2f098d8e394643ad11df2b1027b5b67fde0000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>(@P0 bigint,@P1 datetime2,@P2 datetime2,@P3 varchar(8000),@P4 varchar(8000),@P5 datetime2,)update [dbo].[XYZ] set []=@P0, []=@P1, []=@P2, []=@P3, []=@P4,</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057597045899264" dbid="7" objectname="DB.dbo.ABC" indexname="IX_ABC_XYZFK" id="lock2afc8ca500" mode="X" associatedObjectId="72057597045899264">
<owner-list>
<owner id="process2ba81f8108" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process2ba81fa8c8" mode="S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057596983508992" dbid="7" objectname="DB.dbo.XYZ" indexname="PK_XYZ" id="lock2afd023080" mode="U" associatedObjectId="72057596983508992">
<owner-list>
<owner id="process2ba81fa8c8" mode="S" />
</owner-list>
<waiter-list>
<waiter id="process2ba81f8108" mode="X" requestType="convert" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
【问题讨论】:
-
发布你的死锁图,因为它准确地解释了哪些资源正在死锁。
-
您好 Dale,由于禁用了页面级锁定,因此在密钥级别发生了死锁。涉及的键是表中的 PK 和 FK
-
发布你的死锁图 :)
-
而且这方面的专业知识在dba.stackexchange.com上比较高
-
明确 UPDATE 正在修改哪些列,以及 CASCADE UPDATE 是否有任何外键。以及 UPDATING 事务是否在同一事务中进行过任何先前的更新。不清楚为什么 UPDATEing 进程在表 ABC 的索引上拥有 X 锁。
标签: sql-server orm