同时运行相同的 UPDATE 查询会导致死锁吗?
假设有一个包含数百万条记录的表,我们需要一次性更新数千条记录。
UPDATE TABLEX
SET Column1 = '1'
WHERE Column2 BETWEEN 1 AND 10000
我想知道并发运行这个查询是否会导致死锁,因为每个更新查询可能以不同的顺序获取页/行 U 锁。
换句话说,以下是一种可能的情况。场景是两个并发会话运行相同的查询以更新相同的记录集。
这里,我的假设是每个查询可能会以不同的顺序扫描行,这意味着将以不同的顺序对行进行锁定。
答案 0 :(得分:0)
我同意其他人所说的——从两个不同的会话运行这个特定的查询不会导致死锁,因为不涉及交叉引用。
那么让我们看看当我们尝试时会发生什么......
我这样设置你的 TABLEX:
CREATE TABLE dbo.TableX
(
[id] INT NOT NULL IDENTITY (1,1)
CONSTRAINT [PK_TableX] PRIMARY KEY CLUSTERED
, [Column1] CHAR(1) NULL
, [Column2] INT NULL
CONSTRAINT [UQ_TableX_Column2] UNIQUE
) ;
WITH cte_Nums AS
(
SELECT 1 AS [n]
UNION ALL
SELECT [n] + 1
FROM cte_Nums
WHERE [n] < 500000
)
INSERT
INTO dbo.TableX ( [Column1], [Column2] )
SELECT 'x', [n]
FROM cte_Nums
OPTION ( MAXRECURSION 0 ) ;
GO
然后我从 2 个不同的会话(spids 61 和 58)运行相同的 UPDATE 查询,让事务挂起以查看使用了什么锁:
BEGIN TRAN ;
UPDATE dbo.TableX
SET [Column1] = '1'
WHERE [Column2] BETWEEN 1 AND 10000 ;
然后,在第三个会话中,我运行 sp_lock
来获取锁定信息:
EXEC sp_lock 61, 58 ;
结果如下:
蜘蛛 | 出价 | 对象 ID | IndId | 类型 | 资源 | 模式 | 状态 |
---|---|---|---|---|---|---|---|
58 | 11 | 0 | 0 | 数据库 | S | 赠款 | |
61 | 11 | 0 | 0 | 数据库 | S | 赠款 | |
61 | 11 | 565577053 | 0 | 标签 | X | 赠款 | |
58 | 11 | 565577053 | 0 | 标签 | IX | 等待 |
因此,无论如何,在这种情况下,SQL Server 将整个表上的排他 (X) 锁授予第一个查询 (spid 61),从而防止第二个查询 (spid 58) 接触任何行直到第一次更新完成。
根据您提供的示例,您的问题的答案是否定的。同样的 UPDATE 查询,从不同的会话并发运行,不会导致死锁,因为要更新的锁是针对整个表,而不是单个行。