我有一个来自死锁的死锁图,其中一个进程正在执行 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;
这是更新:
UPDATE htt_customers_overlay_ultra SET plan_state = 'Active' WHERE customer_id = 9300;
但是根据死锁图,UPDATE 正在获取 ACCOUNTS.ACCOUNT0 上的锁,这是 ACCOUNTS 表的 PK (CI)。覆盖表中没有外键。有一些我目前无权查看的默认约束。
我已经查看了 SSMS 和 SQL Sentry Plan Explorer Pro 中的死锁图,但我并不明智。
以下是执行计划:
我想找出它为什么会得到这个锁,然后是序列化这些调用的最佳方法。
我知道的事情我已经告知客户,这些事情与所取的锁有关,但没有解释正在出现的看似无关的锁:
删除 * 并确定所需的列并更改 NCI 以覆盖 - 这可能会使 SELECT 使用更少的锁
确定系统为什么选择另一个进程正在处理的相同数据 - 这可能会完全缓解这两个进程同时运行
SELECT 中有一个表扫描
该
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.213
与2013-01-13 08:49:30.223
。也许在不同的批次中存在前面的语句(因此未在死锁图中显示)实际启动了事务并获得了神秘
X
锁。