在 SQL Server 存储过程中错误地使用 HoldLock

Posted

技术标签:

【中文标题】在 SQL Server 存储过程中错误地使用 HoldLock【英文标题】:Using HoldLock Incorrectly in SQL Server stored procedure 【发布时间】:2013-11-11 21:31:09 【问题描述】:

我相信我错误地使用了HOLDLOCK

我认为这是因为我有一个像队列一样的表。队列从下面的 SQL 接收其项目并在控制台应用程序中一一进行处理。我还没有测试过,但我相信当这个控制台应用程序开始处理这个表时,在一些长选择期间,下面的代码会失败。为什么我认为...因为我在从表队列中获取所有内容并在该控制台应用程序中一一处理它们时记录了 GameID。有趣的是,我认为没有通过的游戏没有在日志中出现,因此我不相信它们被插入到我的队列表中,我相信这是因为下面的HOLDLOCK

想法?

MERGE Test WITH (HOLDLOCK) AS GL
USING (SELECT @GameId AS ID) AS NewTest ON GL.ID = NewTest.ID
WHEN NOT MATCHED THEN
INSERT
(
    Id,
    FailedAttempts,
    DateCreated
)
VALUES
(
    NewTest.ID,
    0,
    SYSDATETIME()
);

【问题讨论】:

你为什么在这里使用 MERGE? 因为我只想插入如果它还没有在表中,它很可能是 MERGE。 或者只是在不存在的地方插入... @AaronBertrand weblogs.sqlteam.com/dang/archive/2009/01/31/… 请阅读sqlperformance.com/2012/08/t-sql-queries/error-handling、mssqltips.com/sqlservertip/2632/… 和mssqltips.com/sqlservertip/3074/… - 请不要再做任何假设了。 【参考方案1】:

我怀疑您的问题与您使用MERGEHOLDLOCK 无关。我认为没有理由在这里引入繁琐的MERGE 语法,因为它没有任何好处,而especially given the potential issues it can cause in other areas。我建议一个很简单的INSERT ... WHERE NOT EXISTS

INSERT dbo.Test(Id, FailedAttempts, DateCreated)
  SELECT @GameId, 0, SYSDATETIME()
  WHERE NOT EXISTS 
  (
    SELECT 1 FROM dbo.Test WITH (HOLDLOCK) 
    WHERE Id = @GameId
  );

由于here 和here 概述的原因,我宁愿这样做而不是盲目地尝试插入并获取 PK 违规 - 在几乎所有情况下,强制 SQL Server 尝试获取异常而不是先检查自己会产生更差的性能。

【讨论】:

以上是关于在 SQL Server 存储过程中错误地使用 HoldLock的主要内容,如果未能解决你的问题,请参考以下文章

sql server中怎样创建保存数据的存储过程

SQL Server 导入和导出向导在使用临时表的存储过程中给出无效对象错误

在SQL Server2005中,下面调用存储过程的语句错误的是:

使用 ssis 包在 SQL Server 代理作业中找不到存储过程错误

如何在sql server的另一个存储过程中执行存储过程

在 ASP.NET MVC 中执行 SQL Server 存储过程时如何防止超时错误?