UPDATE堆表-> RID上的死锁


8

我正在建立一个测试案例,以证明一定的僵局情况,并且需要对正在发生的事情有一些了解。我有一个堆表,方便地称为HeapTable。该表由2个事务类似地更新。

交易1:

BEGIN TRAN

UPDATE HeapTable
SET FirstName = 'Dylan'
WHERE FirstName = 'Ovidiu';

WAITFOR DELAY '00:00:15';

UPDATE HeapTable
SET FirstName = 'Bob'
WHERE FirstName = 'Thierry';

ROLLBACK TRANSACTION

交易2:

BEGIN TRAN

UPDATE HeapTable
SET FirstName = 'Pierre'
WHERE FirstName = 'Michael';

ROLLBACK TRAN

我先触发事务1,紧接着触发事务2。正如预期的那样,事务1将要求一些互斥锁以及一些意图互斥锁。事务2将进入并请求在同一RID上进行更新锁定:

spid dbid   ObjId       IndId   Type    Resource     Mode   Status
55    5     711673583   0       RID     1:24336:10   X      GRANT
57    5     711673583   0       RID     1:24336:10   U      WAIT

看到第二个事务要求对同一RID进行更新锁定,我感到很惊讶,因为我认为这指向单个记录,并且两个更新语句都处理不同的数据。我以某种方式期望在页面级别发生冲突。

当事务1的第二次更新启动时,事务2将被视为死锁受害者,导致事务2的回滚和事务1的完成。

有人可以向我解释为什么第二笔交易尽管更新了不同的记录却需要对同一RID进行更新锁定吗?

我知道如何解决此问题(例如使用索引)。我不是在寻找修复程序,而是在寻找解释为什么2更新处理堆中不同记录的原因会希望锁定相同的RID。我正在使用读取提交隔离。表上没有非聚集索引。

Answers:


18

如果没有索引FirstName,SQL Server必须检查每一行以查看是否符合条件UPDATE

U读取每一行时需要一个更新锁,以防止出现常见的死锁情况。它可能需要一个共享S锁,但仍将被X第一个事务持有的排他锁阻止。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.