MERGE带TABLOCKX与先SELECT加TABLOCKX再MERGE的死锁差异问题
两种MERGE写法的死锁差异原因
- 直接加
TABLOCKX的MERGE写法死锁诱因:
SQL Server的MERGE语句执行分为读取匹配、写入执行两个核心阶段,优化器会先申请共享类锁扫描目标表匹配数据,到写入阶段才尝试升级为排他类锁。即使显式指定TABLOCKX表提示,部分SQL Server版本会在执行计划生成时出现提示优先级偏差:先申请表级意向共享锁(IS)完成读取阶段,后续再尝试升级为表级排他锁(X锁)。多事务并行时,多个事务会同时持有该表的IS锁,每个事务的锁升级操作都需要等待其他事务释放IS锁,形成循环等待的死锁条件,因此会稳定触发死锁。 - 预加锁的MERGE写法无死锁的核心逻辑:
事务内先执行SELECT TOP 1 1 FROM [myTable] WITH (TABLOCKX)时,SQL Server会直接为该事务一次性分配表级排他锁(X锁),且该锁会持续持有到事务提交/回滚。后续执行无表提示的MERGE时,事务已经持有目标表的最高权限X锁,不需要再申请任何新的表级锁,也不会出现锁升级流程。并行事务会按照申请X锁的顺序排队执行,完全破坏了死锁的循环等待条件,因此可以正常运行。
小提示:如果要优化直接MERGE的写法,可以额外补充
HOLDLOCK提示强制锁的持有周期,或者调整事务隔离级别为可序列化,但跨版本兼容性和稳定性不如预申请X锁的方案。
内容的提问来源于stack exchange,提问作者Menno
相关产品推荐
相关产品推荐

