You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server不同行并发删除引发死锁问题求助

死锁场景分析与解决

死锁核心循环

从死锁XML和图形来看,三个事务形成了循环等待链:

  • SPID67(process111c0a04e8):持有Documento表主键索引上某行的X锁(lock112348fb80),等待另一主键键值的S锁(lock113213f500)
  • SPID68(processb8de6eca8):等待lock113213f500的S锁,而该资源被SPID72持有X锁
  • SPID72(process1117804108):持有lock113213f500的X锁,等待SPID67持有的lock112348fb80的S锁

关键原因解析

你提到并发操作未针对同一行,但死锁依然发生,核心原因如下:

  1. 隐式事务的锁持有时长:所有事务都是隐式事务(transactionname="implicit_transaction"),每个事务包含删除+跨表插入操作,锁会在整个事务周期内持续持有,大大增加了锁冲突概率。
  2. 删除操作的索引锁逻辑:即使通过主键id精准删除单条记录,SQL Server在遍历B树索引时,会对路径上的非叶节点键加S锁用于定位目标行。如果并发删除的行在B树中共享同一个上层非叶节点,不同事务对这些节点的锁请求顺序相反时,就会形成死锁。
  3. 隔离级别不影响修改锁:Read Committed(RC)和Read Committed Snapshot(RCSI)的区别仅在于读操作是否加锁,但修改操作(删除)依然会对目标行加X锁,对索引路径加S锁,因此无法避免这类死锁。

解决方案建议

  • 缩短事务时长:将隐式事务改为显式事务,在删除+插入操作完成后立即提交,减少锁的持有时间。示例:
    BEGIN TRANSACTION
    DELETE FROM Documento WHERE id = @P0;
    -- 执行其他表插入操作
    COMMIT TRANSACTION;
    
  • 统一锁请求顺序:如果事务中涉及多表操作,确保所有并发事务的操作顺序完全一致(比如先删除Documento再插入其他表,所有事务都遵循这个顺序),避免交叉等待。
  • 优化索引访问路径:检查主键索引的碎片化程度,定期重建或重组索引,减少SQL Server遍历索引时需要访问的非叶节点数量,降低锁冲突概率。
  • 检查触发器/依赖操作:确认Documento表是否存在删除触发器,若触发器中有额外的索引扫描或修改操作,会扩大锁范围,需优化触发器逻辑。

内容的提问来源于stack exchange,提问作者Tiago Schumann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:47:00