HOLDLOCK对UPDLOCK有什么影响?

时间:2009-10-06 07:53:41

标签: sql-server tsql locking

我见过很多HOLDLOCK提示与UPDLOCK(like this)结合使用的例子。但是Microsoft's documentation这些提示使得看起来HOLDLOCK应该是多余的,因为UPDLOCK已经持续锁定直到事务结束。 (似乎也说HOLDLOCK只适用于共享锁。)

如果有的话,HOLDLOCK如何影响查询?

2 个答案:

答案 0 :(得分:61)

影响很大。

Update锁对行进行Update锁定,对页面进行Intent更新,对表/数据库进行共享锁定。

这不会阻止其他查询访问表中的数据,因为页面/数据库上的锁是纯粹的共享锁。他们可能不会通过尝试执行与锁相矛盾的操作来对单个行/页/表进行冲突。如果发生这种情况,请求将在当前锁定后面排队并等待它可以继续运行。

通过使用holdlock,强制查询序列化,独占锁定表,直到操作完成。这可以防止任何人读取表,除非使用了nolock提示,允许可能脏的读取。

要查看效果,请生成示例表'foo'并在其中放入一些垃圾数据。

begin tran

select * from foo with (updlock)
where tableid = 1
-- notice there is no commit tran

打开另一个窗口并尝试:

select * from foo

行返回,现在提交原始查询事务。重新运行它也改为使用holdlock:

begin tran

select * from foo with (updlock, holdlock)
where tableid = 1

返回到另一个窗口并尝试再次选择数据,查询将不会返回值,因为它被独占锁阻止。在第一个窗口上提交事务,第二个查询的结果将显示,因为它不再被阻止。

最终测试是使用nolock,使用updlock和holdlock再次运行事务。然后在第二个窗口中运行以下命令:

select * from foo (nolock)

结果将自动返回,因为您已接受脏读的风险(未提交读取)。

所以它被认为会产生很大的影响,因为你强制对该表进行序列化操作,这可能是你想要的(取决于正在进行的更新),或者会在该表上创建一个非常大的瓶颈。如果每个人都使用长时间运行的事务来处理繁忙的表,那么它将导致应用程序中的重大延迟。

与所有SQL功能一样,如果使用正确,它们可能很强大,但错误使用功能/提示可能会导致严重问题。当我必须覆盖引擎时,我更喜欢使用提示作为最后的手段 - 而不是默认方法。

按要求编辑:在SQL 2005,2008,2008R2(所有企业版)中测试 - 全部安装在几乎默认的设置上,使用所有默认设置创建测试数据库(仅输入数据库的名称)。

答案 1 :(得分:13)

安德鲁的回答是正确的,根据MSDN文档,但我测试了2008R2和2012,我没有看到这种行为所以请自己测试

我看到的行为如下:

首先在游戏数据库上运行它。

CREATE TABLE [dbo].[foo](
    [tableid] [int] IDENTITY(1,1) NOT NULL,
    [Col2] [varchar](100) NOT NULL,
    CONSTRAINT [PK_foo] PRIMARY KEY CLUSTERED 
    (
        [tableid] ASC
    )
)

...然后放几行。

现在将此代码粘贴到两个查询标签中(更改标签2中的“标签一”文字):

begin tran

select * from foo with (UPDLOCK, HOLDLOCK)
where tableid = 1

UPDATE foo SET Col2 = 'tab one'
where tableid = 1

commit tran

并将其放入另一个标签3

select * from foo
where tableid = 1
  1. 确保您指向表格所在的游戏数据库。

  2. 标签1 中突出显示所有内容更新声明并执行。

  3. 标签2 中执行相同操作,您会发现标签2无法完成且仍在执行中。

  4. 现在在我完成的环境中的标签3 中执行简单的选择。

  5. 突出显示标签1 中的更新语句并执行它(暂时不进行提交),您将看到标签2仍处于执行状态。

  6. 继续执行标签1 中的提交... 标签2 现在将完成选择...您可以运行其余的。