在看似不相关的表上的索引上锁定的死锁图

Cad*_*oux 7 sql-server deadlock locking

我有一个死锁图,其中一个进程正在执行 SELECT 并且一个进程正在执行 UPDATE。这似乎是 SELECT 获取 NCI 锁以执行连接,然后获取 CI 锁以通过查找检索所有数据的经典案例。UPDATE 使用 CI 锁执行更新,然后需要锁定 NCI,因为更新会导致状态更改,并且 NCI 有助于按状态查找项目。

问题是 UPDATE 想要的锁之一不在它正在更新的表上,我找不到为什么会发生这种情况。

这是选择:

SELECT *,
       RIGHT(c.CC_NUMBER, 4) AS CC_LAST_4,
       DATEDIFF(ss, '1970-01-01', plan_started ) plan_started_epoch,
       DATEDIFF(ss, '1970-01-01', plan_expires ) plan_expires_epoch
FROM customers c, accounts a, parent_cos pc, htt_customers_overlay_ultra u
WHERE c.customer_id = a.customer_id
AND   u.customer_id = c.customer_id
AND   a.cos_id=pc.cos_id
AND   u.customer_id = 9300;
Run Code Online (Sandbox Code Playgroud)

这是更新:

UPDATE htt_customers_overlay_ultra SET plan_state = 'Active'  WHERE customer_id = 9300;
Run Code Online (Sandbox Code Playgroud)

但是根据死锁图,UPDATE是在ACCOUNTS.ACCOUNT0上获取锁,也就是ACCOUNTS表的PK(CI)。覆盖表中没有外键。有一些我目前无权查看的默认约束。

我查看了 SSMS 和 SQL Sentry Plan Explorer Pro 中的死锁图,但并不明智。

以下是执行计划:

对于选择

对于更新

我想找出为什么它会获得此锁,然后是序列化这些调用的最佳方法。

我所知道的事情,我已经通知了客户,这些事情与所采取的锁有关,但不要解释正在出现的看似无关的锁:

删除 * 并确定所需的列并更改 NCI 以使其成为覆盖 - 这可能会使 SELECT 使用更少的锁

确定系统为什么选择另一个进程正在处理的相同数据 - 这可能会完全缓解这两个进程同时运行的情况

SELECT中有表扫描

Mar*_*ith 6

UPDATE查询X在“dbo.ACCOUNTS”上的一个键上有一个锁,阻止了它SELECT获得一个S锁。

SELECT查询S在 的键上有一个锁htt_customers_overlay_ultra。该UPDATE查询有一个U在同一个按键锁和被阻止试图将其转换成一个X锁。

的执行计划UPDATE根本没有功能Accounts,所以没有明显的理由让它在 上有一个键锁Accounts。更新事务0.01在批处理开始前几秒钟开始。2013-01-13 08:49:30.2132013-01-13 08:49:30.223.

也许在不同的批处理中有一个前面的语句(因此没有显示在死锁图中)实际上启动了事务并获取了神秘的X锁。

  • @Martin Smith:你的解释对我来说似乎很合乎逻辑。另一件事可能会证明您的答案 - 在第二个查询(更新)`trancount="2"` 的转储中。我相信这意味着有 2 个`开始交易`......这反过来可以解释为什么转储没有`更新帐户`...... (2认同)