SELECT 上怎么可能出现死锁

How is a deadlock possible on a SELECT

我是 运行 游标内的一个过程。经过多次成功的迭代,我得到了这个: Transaction (Process ID 104) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

我不会发布完整的详细信息,因此我不希望得到精细的调试答案。事实:

  1. 我确定没有其他人(包括我自己在另一个会话中)在使用该过程,因为我正在开发它并且
  2. 此事务在执行 select 时“卡住了”(我看到来自 dm exec 请求的 运行 查询)

如果我的 2 点没记错的话,是否有可能出现死锁?死锁不会要求资源的所有相关用户都对它们执行写操作,这会在资源请求图中创建一个循环吗?我理解 select 中的超时错误,但无法理解死锁。我错过了什么?


一个更新:

我放弃了进一步的调试,因为我注意到我认为存在的索引并不存在。创建时,性能还可以。

但是,为了保持这个有用并希望得到一个答案,这里是我调查的更多内容、一些事实和对评论的想法:

首先,sql服务器版本是2008,我知道这个是不支持的。我无权提出建议,更不用说更新服务器了。

我发现 Jeroen Mostert 的评论很有趣。 “过去”有多少?我在 sys.dm_os_waiting_tasks 中注意到会话被自身多次阻塞,等待类型为 CXPACKET。我做了一些搜索,但选项(maxdop 1)没有解决问题。但是,请记住不存在的索引会导致糟糕的性能。难道是附加了正确的并行度,但是操作太多了?尽管如此,我还是亲眼目睹了巨大的dm_exec_requests.wait_time。所以,即使查询很糟糕,我还是相信周围有奇怪的(死)锁。

如果 answer/comment 想出具体的 queries/steps 来追踪问题,我很乐意重新创建它。

如果其他人正在使用 table,SELECT 可能会导致死锁。

此示例几乎 100% 从 Brent Ozar's video on deadlocks 中删除,但将一个命令更改为 SELECT。

首先,创建两个 tables

CREATE TABLE Lefty (ID int PRIMARY KEY)
CREATE TABLE Righty (ID int PRIMARY KEY)
INSERT INTO Lefty (ID)  VALUES (1)
INSERT INTO Righty (ID) VALUES (2)

然后在SSMS中打开两个windows。首先放这段代码(还没有运行)

BEGIN TRAN
UPDATE Lefty SET ID = 5

SELECT * FROM Righty
COMMIT TRAN

在第二个 window 中输入此代码(也不要 运行)。

BEGIN TRAN
UPDATE Righty SET ID = 5
UPDATE Lefty SET ID = 5
COMMIT TRAN

现在,在第一个 window、运行 中的前两个命令 (BEGIN TRAN AND UPDATE LEFTY)。 那开始。

第二个window,运行整个交易。它坐在那里等待您的第一个 window,并将永远等待。

在第window,回去运行的SELECT * FROM RightyCOMMIT TRAN。 5, 4, 3, 2, 1 Boom 死锁 - 因为第二个 window 已经锁定了 table,因此第一个 window 中的 SELECT 不能运行(第二个 window 不能 运行 因为第一个锁定了它需要的 table。

(我想重申 - 这是 Brent Ozar 的演示,不是我的!我只是传递它。确实,我推荐他们)。