Skip to content
Advertisement

Using HoldLock Incorrectly in SQL Server stored procedure

I believe I am using HOLDLOCK incorrectly.

The reason I think this is because I have a table that acts like a queue. The queue receives its items from the SQL below and gets processed, one by one in a console application. I haven’t tested yet but I believe when this console application starts processing this table, during some of the long selects the code below fails. Why do I think that…because I am logging the GameID when grabbing everything from the table queue and processing them one by one in that console application. The funny thing is the games that I believe didn’t make it through didn’t make it in the log, therefore I dont believe they are being inserted in my queue table and I believe it’s because of the HOLDLOCK below.

Thoughts?

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()
);

Advertisement

Answer

I suspect your issue is unrelated to your use of MERGE or HOLDLOCK. I see no reason to introduce cumbersome MERGE syntax here, since it provides no benefit, and especially given the potential issues it can cause in other areas. I suggest a very simple 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
  );

I’d prefer this over just blindly trying to insert and getting a PK violation for the reasons outlined here and here – in almost all cases, forcing SQL Server to try and get an exception instead of checking yourself first will yield worse performance.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement