【问题标题】:UPDATE heap table - Deadlock on RID更新堆表 - RID 上的死锁
【发布时间】:2016-10-14 13:46:47
【问题描述】:

我正在设置一个测试用例来证明某个死锁场景,并且需要对正在发生的事情有所了解。 我有一个堆表,通常称为 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 上更新锁,尽管更新了不同的记录?

【问题讨论】:

  • 这个 DBA 问题应该在 DBA.SE 上吗?
  • @ajeh 总是发现两者之间的界限有些模糊。如果您认为它在那里有更多用途,我会在那里发布。
  • 这里完全没问题。不用担心。
  • 在 DBA.SE 上,您会得到专业 DBA 的更多关注,这里有更多的开发人员闲逛。归根结底,这取决于您的个人喜好,但我相信在那里您可以得到那些每天关注这些问题的人的更多关注。

标签: sql-server deadlock


【解决方案1】:

有人可以解释一下为什么第二个事务需要在同一个 RID 上更新锁,尽管更新了不同的记录?

这可以改写为,当没有索引存在时,Update 语句如何获取需要更新的表上的锁..

SQL在Page上获取一个意向排他锁,然后在读取之前尝试在该页的行上获取U锁,如果匹配到要更新的值,这个锁将被转换为X锁。 .

这种U锁策略是为了确保不会在同一行上使用其他不兼容的锁

请参阅下面由 Kalen Delaney 提供的链接,了解有关相同内容的详细信息

http://sqlblog.com/blogs/kalen_delaney/archive/2009/11/13/update-locks.aspx

【讨论】:

  • 那么如果我理解正确的话,第二个事务会尝试获取页面中所有记录的更新锁,只是试图找到它实际需要的记录?
  • 是的,当没有索引时,必须扫描每条记录才能找到
  • 感谢您为我解决这个问题并加深我对此的了解。你太棒了!
猜你喜欢
  • 1970-01-01
  • 2017-10-18
  • 2017-03-31
  • 1970-01-01
  • 1970-01-01
  • 2020-10-25
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多