SELECT TABLOCKX then MERGE vs MERGE with TABLOCKX - sql-server

I would have thought that the following query's would have the same result:
MERGE [myTable] AS T WITH (TABLOCKX)
...
SELECT TOP 1 1 FROM [myTable] WITH (TABLOCKX);
MERGE [myTable] AS T
...
However, when running my MERGE-statement parellel from multiple processes, the first one will result in deadlocks while the second one runs just fine. Am I missing something here?
I should note that it runs within a transaction.
Edit
I have created a sample DDL and testdata to recreate the issue:
DROP TABLE IF EXISTS [dbo].[myReference]
GO
DROP TABLE IF EXISTS [dbo].[myTable]
GO
CREATE TABLE [dbo].[myTable](
[Primary key] [int] IDENTITY(1,1) NOT NULL,
[Dataset key] [int] NOT NULL,
[Key] [int] NOT NULL,
CONSTRAINT [PK myTable] PRIMARY KEY CLUSTERED ([Primary key] ASC)
)
GO
CREATE TABLE [dbo].[myReference](
[Foreign key] INT NOT NULL,
CONSTRAINT [FK myReference myTable] FOREIGN KEY ([Foreign key]) REFERENCES [dbo].[myTable] ([Primary key]) ON DELETE CASCADE
)
GO
DROP PROCEDURE IF EXISTS [dbo].[usp]
GO
CREATE PROCEDURE [dbo].[usp] #DatasetKey INT AS
WITH Val AS (
SELECT *
FROM ( VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
) s ([Value])
)
SELECT t1.[Value]
+ (t2.[Value] - 1) * 10
+ (t3.[Value] - 1) * 100
+ (t4.[Value] - 1) * 1000
+ (t5.[Value] - 1) * 10000
+ (t6.[Value] - 1) * 100000
AS [Key]
INTO #t
FROM Val t1
cross apply Val t2
cross apply Val t3
cross apply Val t4
cross apply Val t5
cross apply Val t6
;
--SELECT TOP 1 1 FROM [dbo].[myTable] WITH (TABLOCKX);
MERGE [dbo].[myTable] WITH (TABLOCKX) AS T
USING #t AS S
ON T.[Dataset key] = #DatasetKey
AND T.[Key] = S.[Key]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([Dataset key], [Key]) VALUES (#DatasetKey, S.[Key])
WHEN NOT MATCHED BY SOURCE AND T.[Dataset key] = #DatasetKey THEN
DELETE
;
GO
EXEC [dbo].[usp] 1
GO
EXEC [dbo].[usp] 2
GO
INSERT INTO [dbo].[myReference]
SELECT [Primary key]
FROM [dbo].[myTable]
GO
When running the following two transactions simultaneously, the result will be a deadlock every single time.
TRAN 1
BEGIN TRY;
BEGIN TRANSACTION;
exec [dbo].[usp] 1;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
DECLARE #XactState INT = XACT_STATE();
IF #XactState <> 0
ROLLBACK TRANSACTION;
THROW;
END CATCH;
TRAN 2
BEGIN TRY;
BEGIN TRANSACTION;
exec [dbo].[usp] 2;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
DECLARE #XactState INT = XACT_STATE();
IF #XactState <> 0
ROLLBACK TRANSACTION;
THROW;
END CATCH;
Deadlock report
<deadlock>
<victim-list>
<victimProcess id="process273cd96d468" />
</victim-list>
<process-list>
<process id="process273cd96d468" taskpriority="0" logused="0" waitresource="OBJECT: 42:1282103608:0 " waittime="2356" ownerId="2255393274" transactionname="user_transaction" lasttranstarted="2021-11-26T16:11:20.080" XDES="0x296a4fb64d0" lockMode="X" schedulerid="4" kpid="19904" status="suspended" spid="67" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2021-11-26T16:11:20.080" lastbatchcompleted="2021-11-26T16:11:20.077" lastattention="1900-01-01T00:00:00.077" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SV00415" hostpid="21276" loginname="VIECURI\mhoogeveen" isolationlevel="read committed (2)" xactid="2255393274" currentdb="42" currentdbname="Test20211126KanDaarnaWeg" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
<executionStack>
<frame procname="Test20211126KanDaarnaWeg.dbo.usp" line="29" stmtstart="1050" stmtend="1626" sqlhandle="0x03002a00aaa1534ecba70a01ecad000001000000000000000000000000000000000000000000000000000000">
MERGE [dbo].[myTable] WITH (TABLOCKX) AS T
USING #t AS S
ON T.[Dataset key] = #DatasetKey
AND T.[Key] = S.[Key]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([Dataset key], [Key]) VALUES (#DatasetKey, S.[Key])
WHEN NOT MATCHED BY SOURCE AND T.[Dataset key] = #DatasetKey THEN
DELETE </frame>
<frame procname="adhoc" line="4" stmtstart="72" stmtend="106" sqlhandle="0x020000009f228824b51645ad1d06b456eabe7b2b24f2e8fe0000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
BEGIN TRY;
BEGIN TRANSACTION;
exec [dbo].[usp] 2;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
DECLARE #XactState INT = XACT_STATE();
IF #XactState <> 0
ROLLBACK TRANSACTION;
THROW;
END CATCH; </inputbuf>
</process>
<process id="process273c6c4b088" taskpriority="0" logused="0" waitresource="OBJECT: 42:1250103494:0 " waittime="2994" ownerId="2255393256" transactionname="user_transaction" lasttranstarted="2021-11-26T16:11:19.633" XDES="0x27385bfd080" lockMode="X" schedulerid="1" kpid="8752" status="suspended" spid="53" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2021-11-26T16:11:19.633" lastbatchcompleted="2021-11-26T16:11:19.630" lastattention="1900-01-01T00:00:00.630" clientapp="Microsoft SQL Server Management Studio - Query" hostname="SV00415" hostpid="21276" loginname="VIECURI\mhoogeveen" isolationlevel="read committed (2)" xactid="2255393256" currentdb="42" currentdbname="Test20211126KanDaarnaWeg" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
<executionStack>
<frame procname="Test20211126KanDaarnaWeg.dbo.usp" line="29" stmtstart="1050" stmtend="1626" sqlhandle="0x03002a00aaa1534ecba70a01ecad000001000000000000000000000000000000000000000000000000000000">
MERGE [dbo].[myTable] WITH (TABLOCKX) AS T
USING #t AS S
ON T.[Dataset key] = #DatasetKey
AND T.[Key] = S.[Key]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([Dataset key], [Key]) VALUES (#DatasetKey, S.[Key])
WHEN NOT MATCHED BY SOURCE AND T.[Dataset key] = #DatasetKey THEN
DELETE </frame>
<frame procname="adhoc" line="4" stmtstart="72" stmtend="106" sqlhandle="0x020000002457720d4bb1099d3682fee9760829cab4bbc2be0000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
BEGIN TRY;
BEGIN TRANSACTION;
exec [dbo].[usp] 1;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
DECLARE #XactState INT = XACT_STATE();
IF #XactState <> 0
ROLLBACK TRANSACTION;
THROW;
END CATCH; </inputbuf>
</process>
</process-list>
<resource-list>
<objectlock lockPartition="0" objid="1282103608" subresource="FULL" dbid="42" objectname="Test20211126KanDaarnaWeg.dbo.myReference" id="lock29a7a3f4780" mode="IX" associatedObjectId="1282103608">
<owner-list>
<owner id="process273c6c4b088" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process273cd96d468" mode="X" requestType="convert" />
</waiter-list>
</objectlock>
<objectlock lockPartition="0" objid="1250103494" subresource="FULL" dbid="42" objectname="Test20211126KanDaarnaWeg.dbo.myTable" id="lock28a11c39800" mode="X" associatedObjectId="1250103494">
<owner-list>
<owner id="process273cd96d468" mode="X" />
<owner id="process273cd96d468" mode="X" />
<owner id="process273cd96d468" mode="X" />
<owner id="process273cd96d468" mode="X" />
<owner id="process273cd96d468" mode="X" />
<owner id="process273cd96d468" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process273c6c4b088" mode="X" requestType="wait" />
</waiter-list>
</objectlock>
</resource-list>
</deadlock>

It looks like the difference is that MERGE with TABLOCKX initially does take an IX lock, whereas SELECT ... WITH TABLOCKX does not.
I verified this profiling the lock:acquired event on SQL Server 2019 CU 14, and with smaller tables was able to repro the deadlock. It's an extremely short window where this can happen, and the larger tables didn't allow enough concurrency on my system.
This creates a small window where two sessions could acquire IX table locks and neither will be able to escalate to an X lock.
If you want to serialize a block of code, sp_getapplock is the simplest way.

Related

Multiple updates to same table via stored procedure

I am having recurring deadlocks on my application database and trying to understand what is causing them. Using extended events to track them I have identified two common causes, one via an T-SQL statement in the application and the other using a stored procedure. I'll limit this question just to the stored procedure.
I have a stored procedure called writeNominalTrans, I pass some variables from the software and it will either insert or update a record depending on whether a match is found. The XML Deadlock reports commonly refer to the update statements causing the problems, I'll post both stored procedure and an example XML report below.
I have done some reading to understand Deadlocks but most sources just talk about locking between two tables where as my issues resolve around updating records in a single table and not sure exactly how to resolve this.
I think this issue is that it locks the table by pages, possibly multiple at a time as it searches, looking for the correct row to update. If multiple users call the same procedure at the same time, it causes different pages to be locked, ending up with both waiting on each other to finish and thus a Deadlock. Please correct me if this isnt the case.
Within the stored procedure, there are begin/end statements with multiple update statements and not sure if this is one of the potentially issues. Should I put each update statement within it's own begin/end so it is only trying to do one statement at a time? This is assuming it is firing multiple statements per user and some times there are a larger number of processes than in the example below. Aside from this I'm not sure what else is causing the problem, please if you take a look and lend me your expertise.
Regards
David
Stored Procedure
[dbo].[spWriteNominalTrans]
#Recordkey Int Output,
#NominalDataKey int,
#NominalCode int,
#NominalType int,
#TransDate datetime,
#Memo nvarchar(500),
#debit money,
#Credit money,
#VatValueIN money,
#VatValueOut money,
#VatNLAccount int,
#VatRelationKey int,
#Reference nvarchar(50),
#Period int,
#FiscalYear int,
#UserID int,
#DateStamp datetime,
#Transtype nvarchar(150),
#vatcode int,
#vatrate decimal(18,2),
#GoodsValue money,
#AllowMerge bit,
#VatReconcileKey Integer,
#VatOut bit,
#LocationKey int
AS
IF exists ( select * from TblNominalTrans where TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and transtype = #Transtype and #AllowMerge=1 and Memo=#Memo and #Transtype=Transtype and LocationKey =#LocationKey)
-- do an update
BEGIN
UPDATE TblNominalTrans SET
Memo=#Memo,
Debit = Debit + #Debit ,
Credit = Credit +#Credit,
GoodsValue = GoodsValue + #GoodsValue,
VatValueIN = VatValueIN + #VatValueIN,
VatValueOut = VatValueOut + #VatValueOut,
VatOut = #Vatout,
VatNLAccount=#VatNLAccount,
VatRelationKey=#VatRelationKey,
UserId=#UserId,
DateStamp=#DateStamp,
VatReconcileKey = #VatReconcileKey
WHERE TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and Memo=#Memo and #Transtype=Transtype and LocationKey = #LocationKey
UPDATE TblNominalTrans SET
Credit = Credit - Debit, debit = 0
WHERE TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and Memo=#Memo and #Transtype=Transtype and LocationKey = #LocationKey and credit >= debit and debit > 0
UPDATE TblNominalTrans SET
Debit = Debit - Credit, credit = 0
WHERE TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and Memo=#Memo and #Transtype=Transtype and LocationKey = #LocationKey and debit >= credit and credit > 0
END
ELSE
-- do an insert
BEGIN
INSERT TblNominalTrans (
NominalDataKey,
NominalCode,
NominalType ,
TransDate ,
Memo ,
debit ,
Credit ,
VatValueIN,
VatValueOut ,
VatNLAccount ,
VatRelationKey ,
Reference ,
Period ,
FiscalYear ,
VatOut ,
TransType ,
UserID ,
DateStamp,
vatcode,
vatrate,
Goodsvalue,
VatReconcileKey,
LocationKey)
SELECT
#NominalDataKey ,
#NominalCode ,
#NominalType ,
#TransDate ,
#Memo ,
#debit ,
#Credit ,
#VatValueIN,
#VatValueOut ,
#VatNLAccount ,
#VatRelationKey ,
#Reference ,
#Period,
#FiscalYear,
#VatOut,
#transtype,
#UserID,
#DateStamp,
#vatcode,
#vatrate,
#goodsvalue,
#VatReconcileKey,
#LocationKey
END
Deadlock XML Report
<deadlock>
<victim-list>
<victimProcess id="process2c457dd0ca8" />
</victim-list>
<process-list>
<process id="process2c457dd0ca8" taskpriority="0" logused="0" waitresource="PAGE: 7:1:23277 " waittime="1684" ownerId="1782665" transactionname="UPDATE" lasttranstarted="2022-12-13T09:46:09" XDES="0x2c314a19900" lockMode="U" schedulerid="3" kpid="3212" status="suspended" spid="66" sbid="0" ecid="2" priority="0" trancount="0" lastbatchstarted="2022-12-13T09:46:08.930" lastbatchcompleted="2022-12-13T09:46:08.923" lastattention="1900-01-01T00:00:00.923" clientapp="Liquidity" hostname="TERM-SERVER" hostpid="5228" isolationlevel="read committed (2)" xactid="1782665" currentdb="7" lockTimeout="4294967295" clientoption1="536870944" clientoption2="128024">
<executionStack>
<frame procname="MDT_DB.dbo.spWriteNominalTrans" line="43" stmtstart="2092" stmtend="3384" sqlhandle="0x030007002b291964daa21d01caac000001000000000000000000000000000000000000000000000000000000">
UPDATE TblNominalTrans
SET
Memo=#Memo,
Debit = Debit + #Debit ,
Credit = Credit +#Credit,
GoodsValue = GoodsValue + #GoodsValue,
VatValueIN = VatValueIN + #VatValueIN,
VatValueOut = VatValueOut + #VatValueOut,
VatOut = #Vatout,
VatNLAccount=#VatNLAccount,
VatRelationKey=#VatRelationKey,
UserId=#UserId,
DateStamp=#DateStamp,
VatReconcileKey = #VatReconcileKey
WHERE TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and Memo=#Memo and #Transtype=Transtype and LocationKey = #LocationKe </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 1679370539] </inputbuf>
</process>
<process id="process2c457d96108" taskpriority="0" logused="0" waitresource="PAGE: 7:1:2425 " waittime="1686" ownerId="1782668" transactionname="UPDATE" lasttranstarted="2022-12-13T09:46:09.003" XDES="0x2c45d69d900" lockMode="U" schedulerid="2" kpid="3336" status="suspended" spid="176" sbid="0" ecid="1" priority="0" trancount="0" lastbatchstarted="2022-12-13T09:46:08.817" lastbatchcompleted="2022-12-13T09:46:08.813" lastattention="1900-01-01T00:00:00.813" clientapp="Liquidity" hostname="DESKTOP-O2" hostpid="8728" isolationlevel="read committed (2)" xactid="1782668" currentdb="7" lockTimeout="4294967295" clientoption1="536870944" clientoption2="128024">
<executionStack>
<frame procname="MDT_DB.dbo.spWriteNominalTrans" line="64" stmtstart="4210" stmtend="4886" sqlhandle="0x030007002b291964daa21d01caac000001000000000000000000000000000000000000000000000000000000">
UPDATE TblNominalTrans
SET
Debit = Debit - Credit, credit = 0
WHERE TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and Memo=#Memo and #Transtype=Transtype and LocationKey = #LocationKey and debit >= credit and credit > </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 1679370539] </inputbuf>
</process>
<process id="process2c457d97468" taskpriority="0" logused="0" waitresource="PAGE: 7:1:23277 " waittime="1686" ownerId="1782665" transactionname="UPDATE" lasttranstarted="2022-12-13T09:46:09" XDES="0x2c3ab371cb0" lockMode="U" schedulerid="2" kpid="5808" status="suspended" spid="66" sbid="0" ecid="1" priority="0" trancount="0" lastbatchstarted="2022-12-13T09:46:08.930" lastbatchcompleted="2022-12-13T09:46:08.923" lastattention="1900-01-01T00:00:00.923" clientapp="Liquidity" hostname="TERM-SERVER" hostpid="5228" isolationlevel="read committed (2)" xactid="1782665" currentdb="7" lockTimeout="4294967295" clientoption1="536870944" clientoption2="128024">
<executionStack>
<frame procname="MDT_DB.dbo.spWriteNominalTrans" line="43" stmtstart="2092" stmtend="3384" sqlhandle="0x030007002b291964daa21d01caac000001000000000000000000000000000000000000000000000000000000">
UPDATE TblNominalTrans
SET
Memo=#Memo,
Debit = Debit + #Debit ,
Credit = Credit +#Credit,
GoodsValue = GoodsValue + #GoodsValue,
VatValueIN = VatValueIN + #VatValueIN,
VatValueOut = VatValueOut + #VatValueOut,
VatOut = #Vatout,
VatNLAccount=#VatNLAccount,
VatRelationKey=#VatRelationKey,
UserId=#UserId,
DateStamp=#DateStamp,
VatReconcileKey = #VatReconcileKey
WHERE TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and Memo=#Memo and #Transtype=Transtype and LocationKey = #LocationKe </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 1679370539] </inputbuf>
</process>
<process id="process2c45d6984e8" taskpriority="0" logused="10000" waittime="1624" schedulerid="4" kpid="5024" status="suspended" spid="176" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2022-12-13T09:46:08.817" lastbatchcompleted="2022-12-13T09:46:08.813" lastattention="1900-01-01T00:00:00.813" clientapp="Liquidity" hostname="DESKTOP-O2" hostpid="8728" loginname="LOCAL\debbie.weavers" isolationlevel="read committed (2)" xactid="1782668" currentdb="7" lockTimeout="4294967295" clientoption1="536870944" clientoption2="128024">
<executionStack>
<frame procname="MDT_DB.dbo.spWriteNominalTrans" line="64" stmtstart="4210" stmtend="4886" sqlhandle="0x030007002b291964daa21d01caac000001000000000000000000000000000000000000000000000000000000">
UPDATE TblNominalTrans
SET
Debit = Debit - Credit, credit = 0
WHERE TransDate= #TransDate and NominalCode = #NominalCode and Period = #Period and FiscalYear = #FiscalYear and Reference = #Reference and vatcode = #vatcode and Memo=#Memo and #Transtype=Transtype and LocationKey = #LocationKey and debit >= credit and credit > </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 7 Object Id = 1679370539] </inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="23277" dbid="7" subresource="FULL" objectname="MDT_DB.dbo.tblNominalTrans" id="lock2c3c82bb300" mode="U" associatedObjectId="287811838279680">
<owner-list>
<owner id="process2c457d97468" mode="U" requestType="wait" />
</owner-list>
<waiter-list>
<waiter id="process2c457dd0ca8" mode="U" requestType="wait" />
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="2425" dbid="7" subresource="FULL" objectname="MDT_DB.dbo.tblNominalTrans" id="lock2c431d37300" mode="U" associatedObjectId="287811838279680">
<owner-list>
<owner id="process2c457dd0ca8" mode="U" />
</owner-list>
<waiter-list>
<waiter id="process2c457d96108" mode="U" requestType="wait" />
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="23277" dbid="7" subresource="FULL" objectname="MDT_DB.dbo.tblNominalTrans" id="lock2c3c82bb300" mode="U" associatedObjectId="287811838279680">
<owner-list>
<owner id="process2c45d6984e8" mode="U" />
</owner-list>
<waiter-list>
<waiter id="process2c457d97468" mode="U" requestType="wait" />
</waiter-list>
</pagelock>
<exchangeEvent id="Pipe2c3488ae780" WaitType="e_waitPipeGetRow" nodeId="4">
<owner-list>
<owner id="process2c457d96108" />
</owner-list>
<waiter-list>
<waiter id="process2c45d6984e8" />
</waiter-list>
</exchangeEvent>
</resource-list>
</deadlock>

SQLServer Update Trigger with empty DELETED logical table

I create a update trigger on a table to audit data changes...
the code used is:
ALTER TRIGGER dbo.Tg_table_upd ON dbo.table
FOR UPDATE
AS
DECLARE #DATA DATETIME= GETDATE();
DECLARE #USER VARCHAR(20);
SELECT
#USER = CONVERT(VARCHAR, context_info)
FROM master..sysprocesses
WHERE spid = ##SPID;
INSERT INTO table_LOG
SELECT
*,
#USER,
#DATA,
0
FROM deleted;
END;
Do some tests and its working...when I run a update in dbo.table I got 1 or more rows inserted in may audit table table_log.
But in a strange situation...when a java application run a specific update code (captured by SQL Profiler):
DECLARE #P1 INT;
SET #P1 = 68235;
EXEC sp_prepexec
#P1 OUTPUT,
N'#P0 nvarchar(4000),#P1 bigint,#P2 bigint,#P3 bigint,#P4 bigint,#P5 bigint,#P6 bigint,#P7 bigint,#P8 bigint,#P9 bigint,#P10 bigint,#P11 bigint,#P12 bigint,#P13 bigint,#P14 bigint,#P15 bigint,#P16 bigint,#P17 bigint,#P18 bigint,#P19 bigint,#P20 bigint,#P21 bigint,#P22 bigint,#P23 bigint,#P24 bigint,#P25 bigint,#P26 bigint,#P27 bigint,#P28 bigint,#P29 bigint,#P30 nvarchar(4000)',
N'update table set irc_status=#P0 where (irc_id in (#P1 , #P2 , #P3 , #P4 , #P5 , #P6 , #P7 , #P8 , #P9 , #P10 , #P11 , #P12 , #P13 , #P14 , #P15 , #P16 , #P17 , #P18 , #P19 , #P20 , #P21 , #P22 , #P23 , #P24 , #P25 , #P26 , #P27 , #P28 , #P29)) and irc_status=#P30 ',
N'XXX',
58074,
58079,
58082,
58086,
58091,
58095,
57880,
57879,
57874,
57873,
57953,
57959,
57954,
57960,
57785,
57790,
57779,
57784,
59113,
59110,
59116,
59119,
75840,
75851,
75843,
75852,
75834,
75844,
75842,
N'YYY';
SELECT
#P1;
The source table is updated (6 rows affected)...
But I get no rows in my audit table (table_log)
Looking foward in sql profiler... I can confirm the trigger was accioned but when run the statement
SELECT
*,
#USER,
#DATA,
0
FROM deleted;
SQL profiler shows 0 rows affected... So.. the update was commited...(6 ros affected... the trigger was fired... but have a empty "Deleted" Logical table...
Why??

SQL Server: getting deadlock victim error on a stored procedure without transaction

I have a table called Storage with this design:
CREATE TABLE [dbo].[Storage]
(
[Id] [INT] IDENTITY(1,1) NOT NULL,
[GameId] [INT] NOT NULL,
[UserId] [INT] NOT NULL,
[Status] [TINYINT] NOT NULL,
[CreatedAt] [DATETIME] NOT NULL,
[UpdatedAt] [DATETIME] NULL,
[Data] [NVARCHAR](MAX) NOT NULL,
CONSTRAINT [PK_Storage]
PRIMARY KEY CLUSTERED ([Id] ASC)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
and I get a "deadlock victim error" in stored procedure MMO_Storage_Set:
CREATE PROCEDURE [dbo].[MMO_Storage_Set]
#Data NVARCHAR(MAX),
#GameKey INT,
#UserId INT,
#ErrorCode INT OUT
AS
BEGIN
SET NOCOUNT ON;
-- user must have 1 active session at minimum
IF NOT EXISTS(SELECT Id FROM dbo.[Session] WITH(NOLOCK)
WHERE UserId = #UserId AND ([Status] = 1))
BEGIN
SET #ErrorCode = -3
RETURN
END
DECLARE #GameId INT = NULL
DECLARE #GameStatus TINYINT = NULL
SELECT #GameStatus = [Status], #GameId = Id
FROM dbo.[Game] WITH(NOLOCK)
WHERE ([Key] = #GameKey)
-- Game not found
IF #GameStatus IS NULL
BEGIN
SET #ErrorCode = -5
RETURN
END
-- Game is not valid
IF #GameStatus != 1
BEGIN
SET #ErrorCode = -6
RETURN
END
SET #ErrorCode = 0
IF (NOT EXISTS (SELECT ID FROM [Storage] WITH (NOLOCK)
WHERE [UserID] = #UserId AND [GameId] = #GameId))
BEGIN
INSERT INTO dbo.Storage (GameId, UserId,[Status], CreatedAt, UpdatedAt, Data)
VALUES (#GameId, #UserId, 1, GETDATE(), NULL, #Data)
END
ELSE
BEGIN
UPDATE dbo.Storage
SET Data = #Data, UpdatedAt = GETDATE()
WHERE (GameID = #GameId) AND (UserId = #UserId) AND ([Status] = 1)
END
SET #ErrorCode = 1
END
My error is:
Transaction (Process ID 55) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
I use SQL Server Profiler to trace deadlock, as you can see in deadlock report generated by SQL Server Profiler:
<deadlock>
<victim-list>
<victimProcess id="process10754aca8" />
</victim-list>
<process-list>
<process id="process10754aca8" taskpriority="0" logused="0" waitresource="PAGE: 9:1:1167 " waittime="1302" ownerId="501754107" transactionname="UPDATE" lasttranstarted="2018-02-18T02:21:16.990" XDES="0x270741590" lockMode="U" schedulerid="3" kpid="6700" status="suspended" spid="63" sbid="0" ecid="1" priority="0" trancount="0" lastbatchstarted="2018-02-18T02:21:16.810" lastbatchcompleted="2018-02-18T02:21:16.817" lastattention="1900-01-01T00:00:00.817" clientapp=".Net SqlClient Data Provider" hostname="APP-SOCCER-VAS" hostpid="11332" isolationlevel="read committed (2)" xactid="501754107" currentdb="9" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="SoccerChampion.dbo.MMO_Storage_Set" line="60" stmtstart="2870" stmtend="3132" sqlhandle="0x030009008b0bd114d1f2a4004da8000001000000000000000000000000000000000000000000000000000000">
Update dbo.Storage
Set Data = #Data, UpdatedAt = GETDATE()
WHERE (GameID = #GameId) AND (UserId = #UserId) AND ([Status] = 1 </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 9 Object Id = 349244299] </inputbuf>
</process>
<process id="process136d8d088" taskpriority="0" logused="5384" waitresource="PAGE: 9:1:1167 " waittime="1056" ownerId="501753989" transactionname="UPDATE" lasttranstarted="2018-02-18T02:21:16.773" XDES="0x1767f9ce0" lockMode="U" schedulerid="1" kpid="9920" status="suspended" spid="52" sbid="0" ecid="3" priority="0" trancount="0" lastbatchstarted="2018-02-18T02:21:16.590" lastbatchcompleted="2018-02-18T02:21:16.597" lastattention="1900-01-01T00:00:00.597" clientapp=".Net SqlClient Data Provider" hostname="APP-SOCCER-VAS" hostpid="11332" isolationlevel="read committed (2)" xactid="501753989" currentdb="9" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="SoccerChampion.dbo.MMO_Storage_Set" line="60" stmtstart="2870" stmtend="3132" sqlhandle="0x030009008b0bd114d1f2a4004da8000001000000000000000000000000000000000000000000000000000000">
Update dbo.Storage
Set Data = #Data, UpdatedAt = GETDATE()
WHERE (GameID = #GameId) AND (UserId = #UserId) AND ([Status] = 1 </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 9 Object Id = 349244299] </inputbuf>
</process>
<process id="process1001b7848" taskpriority="0" logused="10000" waittime="654" schedulerid="4" kpid="10028" status="suspended" spid="52" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-02-18T02:21:16.590" lastbatchcompleted="2018-02-18T02:21:16.597" lastattention="1900-01-01T00:00:00.597" clientapp=".Net SqlClient Data Provider" hostname="APP-SOCCER-VAS" hostpid="11332" loginname="SC_Core" isolationlevel="read committed (2)" xactid="501753989" currentdb="9" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="SoccerChampion.dbo.MMO_Storage_Set" line="60" stmtstart="2870" stmtend="3132" sqlhandle="0x030009008b0bd114d1f2a4004da8000001000000000000000000000000000000000000000000000000000000">
Update dbo.Storage
Set Data = #Data, UpdatedAt = GETDATE()
WHERE (GameID = #GameId) AND (UserId = #UserId) AND ([Status] = 1 </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 9 Object Id = 349244299] </inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="1167" dbid="9" subresource="FULL" objectname="SoccerChampion.dbo.Storage" id="lock205c8bb00" mode="U" associatedObjectId="72057594084524032">
<owner-list>
<owner id="process1001b7848" mode="U" />
</owner-list>
<waiter-list>
<waiter id="process10754aca8" mode="U" requestType="wait" />
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="1167" dbid="9" subresource="FULL" objectname="SoccerChampion.dbo.Storage" id="lock205c8bb00" mode="U" associatedObjectId="72057594084524032">
<owner-list>
<owner id="process10754aca8" mode="U" requestType="wait" />
</owner-list>
<waiter-list>
<waiter id="process136d8d088" mode="U" requestType="wait" />
</waiter-list>
</pagelock>
<exchangeEvent id="Pipeb1ff6380" WaitType="e_waitPipeGetRow" nodeId="2">
<owner-list>
<owner id="process136d8d088" />
</owner-list>
<waiter-list>
<waiter id="process1001b7848" />
</waiter-list>
</exchangeEvent>
</resource-list>
</deadlock>
I'm wondering why I get deadlock in an update query without transaction and a read query with nolock!!
Can someone tell me why I'm getting this error and how can I fix it?
Not an answer to locks but I see a problem here
IF (NOT EXISTS (SELECT ID FROM [Storage] WITH (NOLOCK)
WHERE [UserID] = #UserId AND [GameId] = #GameId))
But if it does exists you update
AND ([Status] = 1)
You have not checked for status = 1 so that record may not be there
Search on upsert which uses merge. You can eliminate that IF (NOT EXISTS. This is not a clean up the code type suggestion. It may fix your lock problem. For sure it cannot hurt.
Maybe take an explicit rowlock on the update but table hint is should be a last ditch effort.

Insert/Update set of records

The stored Procedure below used to insert/ update the sql database
ALTER PROCEDURE [dbo].[uspInsertorUpdate]
#dp char(32),
#dv char(32),
#e_num char(12),
#mail varchar(50),
#emerg char(32),
#opt1 char(16),
#stat char(20),
#e_id char(35),
#e_tit varchar(64),
#e_date datetime
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM [dbo].[sampleemployee] WHERE e_id= #e_id)
BEGIN
UPDATE [dbo].[sampleemployee]
SET dp = #dp,
dv = #dv,
e_num = #e_num,
mail = #mail,
emerg = #emerg,
opt1 = #opt1,
stat = #stat,
e_tit = #e_tit,
e_date = #e_date
WHERE e_id = #e_id
END
ELSE
BEGIN
INSERT INTO [dbo].[sampleemployee]( dp, dv, e_num, mail, emerg, opt1, stat, e_id, e_tit, e_date)
VALUES ( #dp, #dv, #e_num, #mail, #emerg, #opt1, #stat, #e_id, #e_tit, #e_date );
END
END;
But it just inserts one row.But, I have set of records from Oracle database which I have to insert/update depending on the e_id in to SQA database.Not sure what needs to be changed.
The conditional statement looks good, but it seems that #e_id is not matching e_id. In cases like this, I write simpler statements for debugging purposes:
IF EXISTS (SELECT 1 FROM [dbo].[sampleemployee] where e_id = 'some known value')
BEGIN
PRINT 'YES'
END
ELSE
BEGIN
PRINT 'NO'
END
Maybe this will help point out something you're overlooking. Is #e_id an exact match for e_id, or do you have some cleanup to do?

Stored procedure to update or insert

I am new to stored procedure and managed to google, to create a stored procedure for inserting or updating the database. The set of records are selected from the Oracle Database and depending on the em_id it hase to be iserted or updated in to the Sql Database table using BizTalk
Trying to create a stored procedure to insert or update records depending on a field.
CREATE PROCEDURE [dbo].[usp_InsertorUpdateDB]
#dp_id char(32),
#dv_id char(32),
#em_number char(12),
#email varchar(50),
#emergency_relation char(32),
#option1 char(16),
#status char(20),
#em_id char(35),
#em_title varchar(64),
#date_hired datetime
AS
MERGE [dbo].[em] AS [Target]
USING (SELECT #dp_id, #dv_id , #em_number, #email, #emergency_relation, #option1, #status, #em_id, #em_title, #date_hired)
AS [Source] ([dp_id], [dv_id], [em_number], [email], [emergency_relation], [option1], [status], [em_id], [em_title], [date_hired])
ON [Target].[em_id] = [Source].[em_id]
WHEN MATCHED THEN
UPDATE SET [dp_id] = [Source].[dp_id],
[dv_id] = [Source].[dv_id],
[em_number] = [Source].[em_number],
[email] = [Source].[email],
[emergency_relation] = [Source].[emergency_relation],
[option1] = [Source].[option1],
[status] = [Source].[status],
[em_id] = [Source].[em_id],
[em_title] = [Source].[em_title],
[date_hired] = [Source].[date_hired]
WHEN NOT MATCHED THEN
INSERT ([dp_id], [dv_id], [em_number], [email], [emergency_relation], [option1], [status], [em_id], [em_title],[date_hired])
VALUES ([Source].[dp_id], [Source].[dv_id], [Source].[em_number], [Source].[email], [Source].[emergency_relation], [Source].[option1], [Source].[status], [Source].[em_id], [Source].[em_title], [Source].[date_hired]);
GO
I asked a question two days before because it was showing
Incorrect syntax near the keyword 'WHEN'.
There was a comment showing the code is prone deadlock. Since I am new to Stored Procedures I dont know how to create a stored procedure for insert or update without deadlocks.I am really stuck.
Merge is the reason for deadlock, you can simply try that
CREATE PROCEDURE [dbo].[usp_InsertorUpdateDB]
#dp_id char(32),
#dv_id char(32),
#em_number char(12),
#email varchar(50),
#emergency_relation char(32),
#option1 char(16),
#status char(20),
#em_id char(35),
#em_title varchar(64),
#date_hired datetime
AS
IF ( (SELECT COUNT(em_id) FROM [dbo].[em] WHERE em_id = #em_id) > 0)
UPDATE [dbo].[em]
SET
[dp_id] = #dp_id,
[dv_id] = #dv_id,
[em_number] = #em_number,
[email] = #email,
[emergency_relation] = #emergency_relation,
[option1] = #option1,
[status] = #status,
[em_id] = #em_id,
[em_title] = #em_title,
[date_hired] = #date_hired
WHERE em_id = #em_id
ELSE
INSERT INTO [dbo].[em] (dp_id, dv_id, em_number, email, emergency_relation, option1, [status], em_id, em_title,date_hired)
VALUES (#dp_id, #dv_id, #em_number, #email, #emergency_relation, #option1, #status, #em_id, #em_title, #date_hired);
GO

Resources