MSSQL, UPDLOCK hint
See original GitHub issueHi,
could you please add an UPDLOCK hint into generated SQL merge query?
currently an upsert operation is translated into this SQL code for MSSQL server.
MERGE INTO [StateChangeSnapshots] WITH (HOLDLOCK) AS [T] USING...
IMHO prefered query should be this:
MERGE INTO [StateChangeSnapshots] WITH (UPDLOCK, HOLDLOCK) AS [T] USING...
HOLDLOCK itself is not good enough to avoid deadlocks, this only imply that a serializable isolation level should be used for that table. And IL serializable itself does not prevent from deadlocks.
As you can see here:
I have plenty of such errors in my scenario.
You can simulate that error yourself with SSMS.
--first tab (connection)
SET TRAN ISOLATION LEVEL READ COMMITTED; --sql server default
DROP TABLE IF EXISTS ##myTable;
CREATE TABLE ##myTable(Id INT)
INSERT INTO ##myTable(Id) VALUES (1);
BEGIN TRAN t1
SELECT * FROM ##myTable with(UPDLOCK, HOLDLOCK) WHERE Id = 1;
--1) run to up here only, then switch to second connection (second tab in SSMS)
UPDATE MT SET Id = 2 FROM ##myTable MT WHERE Id = 1
--3) run UPDATE statement only (transaction for it should still be running)
--AS A RESULT one CONNECTION finishes and the second one ends up with a deadlock
COMMIT TRAN t1
--second tab (connection)
SET TRAN ISOLATION LEVEL READ COMMITTED; --sql server default
BEGIN TRAN t1
SELECT * FROM ##myTable with(UPDLOCK, HOLDLOCK) WHERE Id = 1;
UPDATE MT SET Id = 2 FROM ##myTable MT WHERE Id = 1
--2) run to here only
COMMIT TRAN t1
UPDLOCK does the thing. If you use it, then that query reserves those entries for its further updates.
See
In this case the second query stops (in “select” phase) and waits for the first query till it finishes the update operation and commits its transaction (or do a rollback), only then processing of the second query continues.
Issue Analytics
- State:
- Created 3 years ago
- Comments:9 (1 by maintainers)
Top GitHub Comments
Nice and thanks, I am glad I could provide some hints 😃
The Merge is very complex operation as you can see if you check the execution plan.
Probably you would be able to improve your first solution significantly (merge) by adding an appropriate index. (Which could also avoid the deadlocks)
BR
Wow, that’s a complex solution. There’s a few nice tricks in there that I wasn’t aware of, so I’m going to dig into those.
Here’s the query I ended up with:
BEGIN TRY INSERT INTO [Table] (…) VALUES( … ); END TRY BEGIN CATCH UPDATE [Table] SET … WHERE [Index1] = @index1 AND [Index2] = @index2; END CATCH
It definitively resolved the perf issues I was seeing as well and I’ve not seen a hint of the index deadlock or index collision issues the Upsert was to avoid. The Upsert with MAXDOP was taking 13h of compute time, the new version takes 13s for that same data set. This may be a viable solution for integration into the library, or for those trying to solve this problem for themselves.