更新单个表上的两个不同行时发生死锁

use*_*105 5 sql-server sql-server-2008-r2

读了很多关于死锁的文章,当我以为我很了解它时,问题就来了。

有两笔类似的交易同时进行。它们如下所示:

BEGIN TRAN //read_committed_snapshot ON

//an application sends insert query
INSERT INTO t1 VALUES('Name',15)

//later on application sends update query for the newly inserted row
UPDATE t1 SET name='NewName', number=16 WHERE id = 10 //this ID is the id of the inserted row. 

COMMIT
Run Code Online (Sandbox Code Playgroud)

给定的代码与我在应用程序中使用的代码并不完全相同,但想法是相同的,只是有更多的列。

表t1有主键ID,一些非聚集索引。

同时运行其中两个事务后,就会出现死锁。探查器表示UPDATE t1 SET name='NewName', number=16 WHERE id = :id每个冲突进程的死锁查询都是这样的。

抱歉,我没有死锁的 XML,但探查器告诉我两个进程都有 X 锁,并且都尝试获取 U 锁。

process 1
owner - X
waiter - U

process 2
owner - X
waiter - U
Run Code Online (Sandbox Code Playgroud)

t1两个进程的表都显示为对象,PK_id 索引显示为indexname

那么这里到底发生了什么?每个事务更新同一个表中的不同行,为什么会死锁?

网上的许多例子都说“嘿,这是因为它扫描索引的方式,它扫描一个事务的 pk 索引和另一个事务的其他非聚集索引”,但它们的探查器死锁图在 下显示不同的值indexname,因此这与我不同我有,索引名称是相同的。

有什么想法如何解决这个问题吗?这让我疯狂。我认为启用 read_commissed_snapshot 可以解决这个问题,但我错了。

Ole*_*Dok 4

最有可能的是,您的一项或两项更新使用表/聚集索引扫描来查找要更新的行 - 这通常会导致死锁。检查执行计划。