I need help in analysing the following deadlock xml
<deadlock>
<victim-list>
<victimProcess id="processa9f6f73c28" />
</victim-list>
<process-list>
<process id="processa9f6f73c28" taskpriority="0" logused="0" waitresource="KEY: 5:72057594060013568 (bd1a413b4dd8)" waittime="1759" ownerId="19463226" transactionname="user_transaction" lasttranstarted="2018-05-21T14:43:38.640" XDES="0xa9dec70458" lockMode="X" schedulerid="2" kpid="8068" status="suspended" spid="122" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-21T14:43:38.640" lastbatchcompleted="2018-05-21T14:43:38.637" lastattention="1900-01-01T00:00:00.637" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="19463226" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.RelationshipPair_DeleteByRelationshipIds" queryhash="0x9a6597d902cb7ffa" queryplanhash="0x4f762f1ec930146f" line="7" stmtstart="302" stmtend="566" sqlhandle="0x03000500f540c416e4e82300e7a8000001000000000000000000000000000000000000000000000000000000">DELETE
RP
FROM
[model].RelationshipPair RP
INNER JOIN
#RelationshipIdTable RIT
ON
RP.RelationshipId = RIT.EntityI</frame>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.ModelItem_Relationship_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="20" stmtstart="910" stmtend="1066" sqlhandle="0x030005000d989e702ae82300e7a8000001000000000000000000000000000000000000000000000000000000">EXEC [model].[RelationshipPair_DeleteByRelationshipIds]
#RelationshipIdTabl</frame>
</executionStack>
<inputbuf>Proc [Database Id = 5 Object Id = 1889441805]</inputbuf>
</process>
<process id="processa9f9857088" taskpriority="0" logused="624" waitresource="KEY: 5:72057594060013568 (3f1e49aa6519)" waittime="2779" ownerId="19414353" transactionname="user_transaction" lasttranstarted="2018-05-21T14:43:28.600" XDES="0xaa0a244458" lockMode="RangeS-S" schedulerid="2" kpid="51500" status="suspended" spid="164" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-21T14:43:28.603" lastbatchcompleted="2018-05-21T14:43:28.593" lastattention="2018-05-21T14:38:44.820" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="19414353" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.ModelItem_Generic_Create" queryhash="0x21c1a974c29371a5" queryplanhash="0x60900e552e5614c5" line="17" stmtstart="898" stmtend="1402" sqlhandle="0x030005005dcdd742fde62300e7a8000001000000000000000000000000000000000000000000000000000000">INSERT INTO [model].[ModelItem]
(
[MetamodelItemId],
[ModelItemCategoryId]
)
OUTPUT [inserted].[ModelItemId], [inserted].[MetamodelItemId]
INTO #ModelItemIdsByMetamodelId
SELECT EntityId, #ModelItemCategoryId
FROM #MetamodelItemIdTabl</frame>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.ModelItem_Relationship_Create" queryhash="0x41bf1ae3ccbfaccc" queryplanhash="0x76a3cb6aa572b737" line="134" stmtstart="9960" stmtend="10500" sqlhandle="0x030005009b4fb66e1be82300e7a8000001000000000000000000000000000000000000000000000000000000">INSERT INTO #tempStorage
EXECUTE [model].[ModelItem_Generic_Create]
#MetamodelItemIdTable = #metamodelIds,
#ModelId = #ModelId,
#ModelItemCategoryId = #ModelItemCategoryId,
#DateLastModified = #DateLastModified,
#LastModifiedBy = #LastModifiedB</frame>
</executionStack>
<inputbuf>Proc [Database Id = 5 Object Id = 1857441691]</inputbuf>
</process>
<process id="processa9fb862108" taskpriority="0" logused="43256" waitresource="KEY: 5:72057594060013568 (bd1a413b4dd8)" waittime="40" ownerId="19385479" transactionname="user_transaction" lasttranstarted="2018-05-21T14:43:27.370" XDES="0xa9da75c458" lockMode="RangeS-S" schedulerid="1" kpid="51692" status="suspended" spid="193" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-21T14:43:40.320" lastbatchcompleted="2018-05-21T14:43:40.327" lastattention="1900-01-01T00:00:00.327" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="19385479" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.ModelItem_Generic_Delete" queryhash="0xd6e2f8f770b21179" queryplanhash="0x18df7aa720a890f6" line="80" stmtstart="4110" stmtend="4360" sqlhandle="0x0300050096f1cb4302e72300e7a8000001000000000000000000000000000000000000000000000000000000">DELETE
MI
FROM
[model].ModelItem MI
INNER JOIN
#ModelItemIdTable MIT
ON
MIT.EntityId = MI.ModelItemI</frame>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.ModelItem_Object_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="25" stmtstart="1088" stmtend="1302" sqlhandle="0x0300050061e52c65bce72300e7a8000001000000000000000000000000000000000000000000000000000000">EXEC [model].[ModelItem_Generic_Delete]
#ObjectIdTable,
#MarkAsDeleted,
#DeletedBy,
#DeletedO</frame>
</executionStack>
<inputbuf>Proc [Database Id = 5 Object Id = 1697441121]</inputbuf>
</process>
<process id="processa9e0ddc108" taskpriority="0" logused="2657548" waitresource="KEY: 5:72057594060013568 (3f1e49aa6519)" waittime="2779" ownerId="19456397" transactionname="user_transaction" lasttranstarted="2018-05-21T14:43:30.350" XDES="0xa9dc49c458" lockMode="RangeS-S" schedulerid="2" kpid="55424" status="suspended" spid="85" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-05-21T14:43:30.537" lastbatchcompleted="2018-05-21T14:43:30.530" lastattention="1900-01-01T00:00:00.530" clientapp=".Net SqlClient Data Provider" hostname="RD0003FF430FC8" hostpid="12344" loginname="officearchitect" isolationlevel="read committed (2)" xactid="19456397" currentdb="5" currentdbname="OfficeArchitect_Performance_Test" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.ModelItem_Generic_Delete" queryhash="0xd6e2f8f770b21179" queryplanhash="0x18df7aa720a890f6" line="80" stmtstart="4110" stmtend="4360" sqlhandle="0x0300050096f1cb4302e72300e7a8000001000000000000000000000000000000000000000000000000000000">DELETE
MI
FROM
[model].ModelItem MI
INNER JOIN
#ModelItemIdTable MIT
ON
MIT.EntityId = MI.ModelItemI</frame>
<frame procname="d2558974-73ab-4869-acd2-9cce4009286e.model.ModelItem_Object_Delete" queryhash="0x0000000000000000" queryplanhash="0x0000000000000000" line="25" stmtstart="1088" stmtend="1302" sqlhandle="0x0300050061e52c65bce72300e7a8000001000000000000000000000000000000000000000000000000000000">EXEC [model].[ModelItem_Generic_Delete]
#ObjectIdTable,
#MarkAsDeleted,
#DeletedBy,
#DeletedO</frame>
</executionStack>
<inputbuf>Proc [Database Id = 5 Object Id = 1697441121]</inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594060013568" dbid="5" objectname="d2558974-73ab-4869-acd2-9cce4009286e.model.RelationshipPair" indexname="PK_RelationshipPair_RelationshipPairId" id="lockaa19259180" mode="RangeS-U" associatedObjectId="72057594060013568">
<owner-list>
<owner id="processa9f9857088" mode="RangeS-S" />
</owner-list>
<waiter-list>
<waiter id="processa9f6f73c28" mode="X" requestType="convert" />
</waiter-list>
</keylock>
<keylock hobtid="72057594060013568" dbid="5" objectname="d2558974-73ab-4869-acd2-9cce4009286e.model.RelationshipPair" indexname="PK_RelationshipPair_RelationshipPairId" id="lockaa18438980" mode="RangeX-X" associatedObjectId="72057594060013568">
<owner-list>
<owner id="processa9e0ddc108" mode="RangeS-S" requestType="wait" />
</owner-list>
<waiter-list>
<waiter id="processa9f9857088" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594060013568" dbid="5" objectname="d2558974-73ab-4869-acd2-9cce4009286e.model.RelationshipPair" indexname="PK_RelationshipPair_RelationshipPairId" id="lockaa19259180" mode="RangeS-U" associatedObjectId="72057594060013568">
<owner-list>
<owner id="processa9f6f73c28" mode="U" />
<owner id="processa9f6f73c28" mode="X" requestType="convert" />
</owner-list>
<waiter-list>
<waiter id="processa9fb862108" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594060013568" dbid="5" objectname="d2558974-73ab-4869-acd2-9cce4009286e.model.RelationshipPair" indexname="PK_RelationshipPair_RelationshipPairId" id="lockaa18438980" mode="RangeX-X" associatedObjectId="72057594060013568">
<owner-list>
<owner id="processa9fb862108" mode="RangeX-X" />
</owner-list>
<waiter-list>
<waiter id="processa9e0ddc108" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
Now from what I can understand (this is a bit new to me), the DELETE RP statement was the one that was "victimized", this was due to the INSERT INTO [model].[ModelItem] statement.
The issue occurred with locking on the index PK_RelationshipPair_RelationshipPairId.
What I don't fully understand are the RangeA-B locks. I understand that a range of values are locked on the index. But not quite sure why.
I understand that without the actual sql code it is difficult to see exactly what is going on, but I need some assistance in regards to how to go about diagnosing this.
I've tried to replicate the deadlock by running the DELETE and INSERT INTO statements in two transactions (and not completing or rolling back the insert), but no deadlock so far.
Edit
Transaction scope in C# layer is set as follows
var transactionOptions = return new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
Timeout = TransactionManager.MaximumTimeout
};
using (var transaction = new TransactionScope(TransactionScopeOption.Required, transactionOptions, TransactionScopeAsyncFlowOption.Enabled))
{
await action(transaction);
transaction.Complete();
}
It seems you are using TransactionScope class that is forcing range locks common on serializable isolation level despite you using read commited isolation level. Those range locks lockMode="RangeS-S" are prompt to blocking and deadlocks.`
Despite you specifying Read Committed on the transaction options, TransactionScope is forcing range locks that exist only on serializable isolation as explained here.
Related
I have an API endpoint to delete children of a parent, unless a child is specified. The SQL is:
DELETE FROM
Child
WHERE
ParentID = #ParentID AND
ChildID NOT IN (#ChildIDToKeep);
(This query is sanitised, so ignore the fact that I'm not doing ChildID != #ChildIDToKeep)
The executed SQL is also wrapped in a transaction.
My web application attempts to send hundreds of requests to this endpoint concurrently, so this SQL transaction gets executed concurrently many times. For some reason this is causing a deadlock.
Why am I getting a deadlock, and what can I do to resolve it?
Here is the deadlock XML:
<deadlock>
<victim-list>
<victimProcess id="process25c3045b848" />
</victim-list>
<process-list>
<process id="process25c3045b848" taskpriority="0" logused="6336" waitresource="OBJECT: 14:788354023:0 " waittime="3039" ownerId="39730548" transactionname="user_transaction" lasttranstarted="2021-08-13T13:28:05.690" XDES="0x25c36f9f900" lockMode="IX" schedulerid="1" kpid="6588" status="suspended" spid="70" sbid="4" ecid="0" priority="0" trancount="2" lastbatchstarted="2021-08-13T13:28:05.957" lastbatchcompleted="2021-08-13T13:28:05.957" lastattention="1900-01-01T00:00:00.957" clientapp="Core .Net SqlClient Data Provider" hostname="DER-UK-LAP-101" hostpid="14344" loginname="USERNAME" isolationlevel="serializable (4)" xactid="39730548" currentdb="14" currentdbname="Database" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="2" stmtstart="102" stmtend="500" sqlhandle="0x0200000053d2042c7d4e4199da6b8531c53adb3464bc8b610000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(#ParentID int,#ChildIDToKeep int)
DELETE FROM
Child
WHERE
ParentID = #ParentID AND
ChildID NOT IN (#ChildIDToKeep); </inputbuf>
</process>
<process id="process25c2a462ca8" taskpriority="0" logused="6348" waitresource="OBJECT: 14:788354023:0 " waittime="2901" ownerId="39730549" transactionname="user_transaction" lasttranstarted="2021-08-13T13:28:05.690" XDES="0x25c39560e80" lockMode="IX" schedulerid="2" kpid="2252" status="suspended" spid="63" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2021-08-13T13:28:06.097" lastbatchcompleted="2021-08-13T13:28:06.097" lastattention="1900-01-01T00:00:00.097" clientapp="Core .Net SqlClient Data Provider" hostname="DER-UK-LAP-101" hostpid="14344" loginname="USERNAME" isolationlevel="serializable (4)" xactid="39730549" currentdb="14" currentdbname="Database" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="2" stmtstart="102" stmtend="500" sqlhandle="0x0200000053d2042c7d4e4199da6b8531c53adb3464bc8b610000000000000000000000000000000000000000">
unknown </frame>
<frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
(#ParentID int,#ChildIDToKeep int)
DELETE FROM
Child
WHERE
ParentID = #ParentID AND
ChildID NOT IN (#ChildIDToKeep); </inputbuf>
</process>
</process-list>
<resource-list>
<objectlock lockPartition="0" objid="788354023" subresource="FULL" dbid="14" objectname="Database.dbo.Child" id="lock255443f2580" mode="S" associatedObjectId="788354023">
<owner-list>
<owner id="process25c2a462ca8" mode="S" />
<owner id="process25c2a462ca8" mode="IX" requestType="convert" />
</owner-list>
<waiter-list>
<waiter id="process25c3045b848" mode="IX" requestType="convert" />
</waiter-list>
</objectlock>
<objectlock lockPartition="0" objid="788354023" subresource="FULL" dbid="14" objectname="Database.dbo.Child" id="lock255443f2580" mode="S" associatedObjectId="788354023">
<owner-list>
<owner id="process25c3045b848" mode="S" />
<owner id="process25c3045b848" mode="IX" requestType="convert" />
</owner-list>
<waiter-list>
<waiter id="process25c2a462ca8" mode="IX" requestType="convert" />
</waiter-list>
</objectlock>
</resource-list>
</deadlock>
Here is the deadlock graph:
You've asked for the deadlock by running the transaction in SERIALIZABLE isolation level:
isolationlevel="serializable (4)"
SERIALIZABLE transactions hold shared (S) locks until the end of the transaction, so when you "Select Parent's Children." you acquire and hold a S lock. And it's a table lock since you don't have proper indexing on the table.
SERIALIZABLE enforces its guarantees with deadlocks, see rant here: using new TransactionScope() considered harmful.
So when two sessions take and hold an S lock on the table, neither can acquire the IX lock required to start the DELETE, nor would they be able to acquire the X lock required to complete the DELETE. SERIALIZABLE is just doing its job here, as each session has read data that the other is trying to update, so if allowed to complete, the state of the database would not be the same as if the transactions ran sequentially, which is the definition of SERIALIZABLE. So it's expected one of the transactions must be terminated, and that you would catch and retry if you still needed that work done.
So I would drop to READ_COMMITTED, and put an index on ParentId. You might want to put an UPDLOCK hint on your query to "Select Parent" so two sessions can't run against the same parent concurrently.
I have two SQL queries (MSSQL server):
SELECT [Value]
FROM [dbo].[BigTable]
ORDER BY [Id] DESC
and
UPDATE [dbo].[BigTable]
SET [Value] = [Value]
Where [Id] - Primary clustered key.
When I run them infinitely in the loop I get deadlock, which is obvious. But what is not obvious (for me): why on deadlock graph I get "Owner mode: U" for select statement.
As far as I know select statement can only have shared locks. And here I'm not using any hints or additional transactions to make update lock. Any idea why I see it here?
XML for deadlock is attached
<deadlock-list>
<deadlock victim="process1c094ee5468">
<process-list>
<process id="process1c094ee5468" taskpriority="0" logused="0" waitresource="PAGE: 7:1:1502 " waittime="1289" ownerId="901143" transactionname="SELECT" lasttranstarted="2021-05-05T18:04:54.470" XDES="0x1c094329be8" lockMode="S" schedulerid="6" kpid="22644" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2021-05-05T18:04:54.470" lastbatchcompleted="2021-05-05T18:04:54.453" lastattention="1900-01-01T00:00:00.453" clientapp="Core Microsoft SqlClient Data Provider" hostname="ALEXEY-KLIPILIN" hostpid="3132" loginname="sa" isolationlevel="read committed (2)" xactid="901143" currentdb="7" currentdbname="SampleDb" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtend="92" sqlhandle="0x02000000bf49f5138395d042205ae64888add734815151770000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
SELECT * FROM [dbo].[BigTable] ORDER BY Id DESC </inputbuf>
</process>
<process id="process1c096e1d088" taskpriority="0" logused="100" waitresource="PAGE: 7:1:1503 " waittime="1289" ownerId="901139" transactionname="UPDATE" lasttranstarted="2021-05-05T18:04:54.470" XDES="0x1c08bc84428" lockMode="X" schedulerid="4" kpid="9160" status="suspended" spid="61" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2021-05-05T18:04:54.470" lastbatchcompleted="2021-05-05T18:04:54.397" lastattention="1900-01-01T00:00:00.397" clientapp="Core Microsoft SqlClient Data Provider" hostname="ALEXEY-KLIPILIN" hostpid="3132" loginname="sa" isolationlevel="read committed (2)" xactid="901139" currentdb="7" currentdbname="SampleDb" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtend="88" sqlhandle="0x0200000018eeb102d311fd032bb670822f260841060b64410000000000000000000000000000000000000000">
unknown </frame>
</executionStack>
<inputbuf>
UPDATE [dbo].[BigTable] SET [Value] = [Value] </inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="1502" dbid="7" subresource="FULL" objectname="SampleDb.dbo.BigTable" id="lock1c0884bdd00" mode="X" associatedObjectId="72057594043760640">
<owner-list>
<owner id="process1c096e1d088" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process1c094ee5468" mode="S" requestType="wait"/>
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="1503" dbid="7" subresource="FULL" objectname="SampleDb.dbo.BigTable" id="lock1c0a0a23380" mode="U" associatedObjectId="72057594043760640">
<owner-list>
<owner id="process1c094ee5468" mode="S"/>
</owner-list>
<waiter-list>
<waiter id="process1c096e1d088" mode="X" requestType="convert"/>
</waiter-list>
</pagelock>
</resource-list>
</deadlock>
</deadlock-list>
This just looks like some misrepresentation in the graphical representation.
process1c096e1d088 (the UPDATE) holds a page level X lock on page 1502 and a page level U lock on 1503 and is trying to convert that U lock to an X lock. (requestType="convert")
process1c094ee5468 (the SELECT) holds a page level S lock on 1503 (compatible with the U lock) and is waiting for a page level S lock on 1502.
Because the page lock 1503 is held in both S and U modes it has mode="U" in the deadlock XML and the UI assumes it is held by the blocker in that mode.
Of course if the SELECT transaction was to release its lock on 1503 before requesting the lock on 1502 this deadlock could not arise but I assume there is a good reason for it not doing this (maybe to stop 1502 getting deallocated mid scan and leaving it with no next page to visit).
I'm trying to determine how this deadlock occurred and what fix I need to do to prevent it from happening again.
I've attached deadlock graph image from SSMS, resolution provided by SSMS image is not good, I apologize.
What is going on here is 3 processes are locked in a cycle, all waiting for the lock on the primary key for the table SecurityObject to be released.
The primary key for this table is clustered and is a composite key containing four columns.
The statement that each process is running is shown below. It is a delete command, deleting all records from table that match on a single column. The column is a GUID identifier that is one of the four columns in the composite clustered primary key.
DELETE FROM SecurityObject WHERE col1 = #val1
Where col1 is one of the four columns in the primary key.
I'm struggling to understand is how this scenario could have happened? How can there be a deadlock scenario for a primary key lock?
Below is the deadlock xml graph:
<deadlock>
<victim-list>
<victimProcess id="processaeabf84108"/>
</victim-list>
<process-list>
<process id="processaeabf84108" taskpriority="0" logused="0" waitresource="KEY: 14:72057594041925632 (00f78314b62e)" waittime="1754" ownerId="6629325" transactionname="user_transaction" lasttranstarted="2017-08-04T15:16:55.747" XDES="0xaea526f498" lockMode="X" schedulerid="2" kpid="16620" status="suspended" spid="73" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-08-04T15:16:55.747" lastbatchcompleted="2017-08-04T15:16:55.747" lastattention="1900-01-01T00:00:00.747" clientapp=".Net SqlClient Data Provider" hostname="RDXP0165C9JAWIE" hostpid="19084" loginname="REDMOND\RDXP0165C9JAWIE$" isolationlevel="read committed (2)" xactid="6629325" currentdb="14" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="SecurityAuthorization.DB.dbo.spDeleteAllSecurityObjects" line="5" stmtstart="342" stmtend="474" sqlhandle="0x03000e00b56a9938f8fcba00c3a7000001000000000000000000000000000000000000000000000000000000"> DELETE FROM [SecurityObject] WHERE [EnvironmentId] = #EnvironmentI </frame>
</executionStack>
<inputbuf> Proc [Database Id = 14 Object Id = 949578421] </inputbuf>
</process>
<process id="processaea64a9468" taskpriority="0" logused="0" waitresource="KEY: 14:72057594041925632 (e0caa7da41f0)" waittime="3981" ownerId="6629329" transactionname="user_transaction" lasttranstarted="2017-08-04T15:16:55.750" XDES="0xaea9602408" lockMode="X" schedulerid="1" kpid="14152" status="suspended" spid="76" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-08-04T15:16:55.750" lastbatchcompleted="2017-08-04T15:16:55.750" lastattention="1900-01-01T00:00:00.750" clientapp=".Net SqlClient Data Provider" hostname="RDXP0165C9JAWIE" hostpid="19084" loginname="REDMOND\RDXP0165C9JAWIE$" isolationlevel="read committed (2)" xactid="6629329" currentdb="14" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="SecurityAuthorization.DB.dbo.spDeleteAllSecurityObjects" line="5" stmtstart="342" stmtend="474" sqlhandle="0x03000e00b56a9938f8fcba00c3a7000001000000000000000000000000000000000000000000000000000000"> DELETE FROM [SecurityObject] WHERE [EnvironmentId] = #EnvironmentI </frame>
</executionStack>
<inputbuf> Proc [Database Id = 14 Object Id = 949578421] </inputbuf>
</process>
<process id="processaea686fc28" taskpriority="0" logused="884" waitresource="KEY: 14:72057594041925632 (e0caa7da41f0)" waittime="2105" ownerId="6638253" transactionname="user_transaction" lasttranstarted="2017-08-04T15:16:57.627" XDES="0xaea9460e58" lockMode="X" schedulerid="2" kpid="6528" status="suspended" spid="79" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-08-04T15:16:57.627" lastbatchcompleted="2017-08-04T15:16:57.627" lastattention="1900-01-01T00:00:00.627" clientapp=".Net SqlClient Data Provider" hostname="RDXP0165C9JAWIE" hostpid="19084" loginname="REDMOND\RDXP0165C9JAWIE$" isolationlevel="read committed (2)" xactid="6638253" currentdb="14" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="SecurityAuthorization.DB.dbo.spDeleteAllSecurityObjects" line="5" stmtstart="342" stmtend="474" sqlhandle="0x03000e00b56a9938f8fcba00c3a7000001000000000000000000000000000000000000000000000000000000"> DELETE FROM [SecurityObject] WHERE [EnvironmentId] = #EnvironmentI </frame>
</executionStack>
<inputbuf> Proc [Database Id = 14 Object Id = 949578421] </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594041925632" dbid="14" objectname="SecurityAuthorization.DB.dbo.SecurityObject" indexname="PK__Security__185B78FE57F79F91" id="lockaead1a0680" mode="X" associatedObjectId="72057594041925632">
<owner-list>
<owner id="processaea686fc28" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="processaeabf84108" mode="X" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594041925632" dbid="14" objectname="SecurityAuthorization.DB.dbo.SecurityObject" indexname="PK__Security__185B78FE57F79F91" id="lockae6d468f80" mode="X" associatedObjectId="72057594041925632">
<owner-list>
<owner id="processaeabf84108" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="processaea64a9468" mode="X" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594041925632" dbid="14" objectname="SecurityAuthorization.DB.dbo.SecurityObject" indexname="PK__Security__185B78FE57F79F91" id="lockae6d468f80" mode="X" associatedObjectId="72057594041925632">
<owner-list>
<owner id="processaea64a9468" mode="X" requestType="wait"/>
</owner-list>
<waiter-list>
<waiter id="processaea686fc28" mode="X" requestType="wait"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
Here is execution plan of stored procedure:
After further testing, I've managed to isolate the root cause of deadlock scenario to be concurrent calls to both DeleteAll (delete subset of records in table) and Insert (inserts a record that matches the criteria of the DeleteAll).
The exact sequence of events that leads to the deadlock scenario remains unclear, but the issue is solved by setting isolation level to serializable.
It is an acceptable side effect that it will hurt performance (for my scenario, we do not care about this operations performance because these operations are not being waited on, it is a fire and forget process).
I am getting an error "Cannot select a record in SalesParmSubTable.
Deadlock, where one or more users have simultaneously locked the whole table or part of it".
I used sql profiler for getting the deadlock trace. Can someone please help to rectify it.
<?xml version="1.0" encoding="UTF-8"?>
<deadlock-list>
<deadlock victim="process58d048">
<process-list>
<process id="process58d048" taskpriority="0" logused="5784" waitresource="PAGE: 16:1:16714223" waittime="1587" ownerId="207752233" transactionname="user_transaction" lasttranstarted="2016-05-07T07:58:32.533" XDES="0x52376d950" lockMode="S" schedulerid="4" kpid="10860" status="suspended" spid="159" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2016-05-07T07:58:32.553" lastbatchcompleted="2016-05-07T07:58:32.553" clientapp="Microsoft Dynamics AX" hostname="*********" hostpid="19816" loginname="************" isolationlevel="read committed (2)" xactid="207752233" currentdb="16" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="100" sqlhandle="0x02000000d3d2cf1665ba9e17ee49d6dd9bc2fbf295ad7168">SELECT A.DEL_SALESID,A.SALESNAME,A.PARMID,A.ORIGSALESID,A.TABLEREFID,A.DEL_ORIGTABLEREFID,A.JOURNALREFTABLEID,A.JOURNALREFRECID,A.SUBID,A.CREATEDDATETIME,A.CREATEDBY,A.RECVERSION,A.RECID FROM SALESPARMSUBTABLE A WHERE ((A.DATAAREAID=#P1) AND (A.PARMID=#P2)) AND NOT EXISTS (SELECT 'x' FROM SALESPARMLINE B WHERE ((B.DATAAREAID=#P3) AND (((B.PARMID=A.PARMID) AND (B.TABLEREFID=A.TABLEREFID)) AND (B.ORIGSALESID=A.ORIGSALESID)))) ORDER BY A.DATAAREAID,A.PARMID,A.DEL_SALESID</frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">unknown</frame>
</executionStack>
<inputbuf>(#P1 nvarchar(5),#P2 nvarchar(21),#P3 nvarchar(5))SELECT A.DEL_SALESID,A.SALESNAME,A.PARMID,A.ORIGSALESID,A.TABLEREFID,A.DEL_ORIGTABLEREFID,A.JOURNALREFTABLEID,A.JOURNALREFRECID,A.SUBID,A.CREATEDDATETIME,A.CREATEDBY,A.RECVERSION,A.RECID FROM SALESPARMSUBTABLE A WHERE ((A.DATAAREAID=#P1) AND (A.PARMID=#P2)) AND NOT EXISTS (SELECT 'x' FROM SALESPARMLINE B WHERE ((B.DATAAREAID=#P3) AND (((B.PARMID=A.PARMID) AND (B.TABLEREFID=A.TABLEREFID)) AND (B.ORIGSALESID=A.ORIGSALESID)))) ORDER BY A.DATAAREAID,A.PARMID,A.DEL_SALESID</inputbuf>
</process>
<process id="process572988" taskpriority="0" logused="5800" waitresource="PAGE: 16:1:16714223" waittime="1576" ownerId="207752211" transactionname="user_transaction" lasttranstarted="2016-05-07T07:58:32.530" XDES="0x865e1950" lockMode="S" schedulerid="3" kpid="21628" status="suspended" spid="154" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2016-05-07T07:58:32.563" lastbatchcompleted="2016-05-07T07:58:32.560" clientapp="Microsoft Dynamics AX" hostname="*********" hostpid="19816" loginname="*********" isolationlevel="read committed (2)" xactid="207752211" currentdb="16" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="adhoc" line="1" stmtstart="100" sqlhandle="0x02000000d3d2cf1665ba9e17ee49d6dd9bc2fbf295ad7168">SELECT A.DEL_SALESID,A.SALESNAME,A.PARMID,A.ORIGSALESID,A.TABLEREFID,A.DEL_ORIGTABLEREFID,A.JOURNALREFTABLEID,A.JOURNALREFRECID,A.SUBID,A.CREATEDDATETIME,A.CREATEDBY,A.RECVERSION,A.RECID FROM SALESPARMSUBTABLE A WHERE ((A.DATAAREAID=#P1) AND (A.PARMID=#P2)) AND NOT EXISTS (SELECT 'x' FROM SALESPARMLINE B WHERE ((B.DATAAREAID=#P3) AND (((B.PARMID=A.PARMID) AND (B.TABLEREFID=A.TABLEREFID)) AND (B.ORIGSALESID=A.ORIGSALESID)))) ORDER BY A.DATAAREAID,A.PARMID,A.DEL_SALESID</frame>
<frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">unknown</frame>
</executionStack>
<inputbuf>(#P1 nvarchar(5),#P2 nvarchar(21),#P3 nvarchar(5))SELECT A.DEL_SALESID,A.SALESNAME,A.PARMID,A.ORIGSALESID,A.TABLEREFID,A.DEL_ORIGTABLEREFID,A.JOURNALREFTABLEID,A.JOURNALREFRECID,A.SUBID,A.CREATEDDATETIME,A.CREATEDBY,A.RECVERSION,A.RECID FROM SALESPARMSUBTABLE A WHERE ((A.DATAAREAID=#P1) AND (A.PARMID=#P2)) AND NOT EXISTS (SELECT 'x' FROM SALESPARMLINE B WHERE ((B.DATAAREAID=#P3) AND (((B.PARMID=A.PARMID) AND (B.TABLEREFID=A.TABLEREFID)) AND (B.ORIGSALESID=A.ORIGSALESID)))) ORDER BY A.DATAAREAID,A.PARMID,A.DEL_SALESID</inputbuf>
</process>
</process-list>
<resource-list>
<pagelock fileid="1" pageid="16714223" dbid="16" objectname="AX2009_****.dbo.SALESPARMLINE" id="lock562bdb480" mode="IX" associatedObjectId="72057635944464384">
<owner-list>
<owner id="process572988" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process58d048" mode="S" requestType="convert" />
</waiter-list>
</pagelock>
<pagelock fileid="1" pageid="16714223" dbid="16" objectname="AX2009_****.dbo.SALESPARMLINE" id="lock562bdb480" mode="IX" associatedObjectId="72057635944464384">
<owner-list>
<owner id="process58d048" mode="IX" />
</owner-list>
<waiter-list>
<waiter id="process572988" mode="S" requestType="convert" />
</waiter-list>
</pagelock>
</resource-list>
</deadlock>
</deadlock-list>
I don't think we can solve the deadlock issue by merely knowing a deadlock is occurring...we need to know why or what process is happening.
It looks like it's a cleanup operation or something with sales order posting, because it's looking for SalesParmTable records where the SalesParmLine records don't exist. You can use that query to look for the select statement in code and work backwards to see what process is initiating it.
I'd think a better approach would be, when it's happening, find out what users are doing at the time. Check batch jobs to see if two batch jobs are doing the same thing at the same time.
You may be able to find out what users/processes are causing it by following this blog:
https://blogs.msdn.microsoft.com/amitkulkarni/2011/08/10/finding-user-sessions-from-spid-in-dynamics-ax-2012/
I've strange deadlock graph where the victim chosen by MSSQL server 2008 isn't part of the deadlock loop.
This deadlock is between select and insert.
The deadlock resource is a single table where all selects want waitresource = "KEY: 6:72057594098810880 (ffffffffffff)"
Question1 : Does ffffffffffff here mean they want a full range lock on whole table? Or whole key range? Or something else?
We are following a rule where table will never have a row with primary key id = 0.
There are few places where we do this kind of check
select foo from bar where #someId = 0 OR SomeId = #someId.
I also came to know about that SQL doesn't short-circuit the expression. So if I pass #someId = 0 that doesn't guarantee the other part won't be evaluated. So it's possible that SQL can execute at runtime SomeId = #someId.
Question2 : Since it wasn't able to find 0 in SomeId, SQL will acquire a range lock on whole table (or row) so no one else inserts 0 id. Right?
With that assumption in mind I changed the where clause to this
(CASE
WHEN #someId = 0 THEN 1
WHEN SomeId = #someId THEN 1
ELSE 0
END = 1)
hoping that this will force evaluation order. But I'm wrong. I'm getting the deadlock again.
I've attached the deadlock graph below. I've renamed tables and sprocs involved (Company policy)
Question3 : Do you know what I'm missing here?
<deadlock-list>
<deadlock victim="process722c508">
<process-list>
<process id="process722c508" taskpriority="0" logused="0" waitresource="KEY: 6:72057594098810880 (ffffffffffff)" waittime="6217" ownerId="24219001" transactionname="SELECT" lasttranstarted="2011-05-17T03:29:16.033" XDES="0x80073a40" lockMode="RangeS-S" schedulerid="13" kpid="20436" status="suspended" spid="91" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2011-05-17T03:29:16.033" lastbatchcompleted="2011-05-17T03:29:16.033" clientapp=".Net SqlClient Data Provider" hostname="SOMEHOST" hostpid="28820" loginname="someloginname" isolationlevel="serializable (4)" xactid="24219001" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="fnGetTableResultAByBId" line="44" stmtstart="2246" stmtend="3566" sqlhandle="0x03000600800d7f0bda124000d99e00000000000000000000">
INSERT INTO #ReturnTable
SELECT Foo, Bar
FROM TheOneTable
WHERE ZId = #zId
AND (CASE
WHEN #yId = 0 THEN 1
WHEN YId = #yId THEN 1
ELSE 0
END = 1)
AND (CASE
WHEN #xId = 0 THEN 1
WHEN XId = #xId THEN 1
ELSE 0
END = 1) </frame>
<frame procname="GetViewCByDId" line="9" stmtstart="272" stmtend="2984" sqlhandle="0x03000600c21629025d8f3f00d99e00000100000000000000">
</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 6 Object Id = 36247234] </inputbuf>
</process>
<process id="process7185048" taskpriority="0" logused="0" waitresource="KEY: 6:72057594098810880 (ffffffffffff)" waittime="6217" ownerId="24218992" transactionname="SELECT" lasttranstarted="2011-05-17T03:29:16.030" XDES="0x179980430" lockMode="RangeS-S" schedulerid="13" kpid="30616" status="suspended" spid="79" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2011-05-17T03:29:16.030" lastbatchcompleted="2011-05-17T03:29:16.030" clientapp=".Net SqlClient Data Provider" hostname="SOMEHOST" hostpid="28820" loginname="someloginname" isolationlevel="serializable (4)" xactid="24218992" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="fnGetTableResultAByBId" line="44" stmtstart="2246" stmtend="3566" sqlhandle="0x03000600800d7f0bda124000d99e00000000000000000000">
INSERT INTO #ReturnTable
SELECT Foo, Bar
FROM TheOneTable
WHERE ZId = #zId
AND (CASE
WHEN #yId = 0 THEN 1
WHEN YId = #yId THEN 1
ELSE 0
END = 1)
AND (CASE
WHEN #xId = 0 THEN 1
WHEN XId = #xId THEN 1
ELSE 0
END = 1) </frame>
<frame procname="GetViewCByDId" line="9" stmtstart="272" stmtend="2984" sqlhandle="0x03000600c21629025d8f3f00d99e00000100000000000000">
</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 6 Object Id = 36247234] </inputbuf>
</process>
<process id="process7223048" taskpriority="0" logused="0" waitresource="KEY: 6:72057594098810880 (ffffffffffff)" waittime="5330" ownerId="24235090" transactionname="SELECT" lasttranstarted="2011-05-17T03:29:16.927" XDES="0x840d3b30" lockMode="RangeS-S" schedulerid="15" kpid="23452" status="suspended" spid="88" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2011-05-17T03:29:16.927" lastbatchcompleted="2011-05-17T03:29:16.927" clientapp=".Net SqlClient Data Provider" hostname="SOMEHOST" hostpid="28820" loginname="someloginname" isolationlevel="serializable (4)" xactid="24235090" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="GetOneRowEByFId" line="11" stmtstart="260" stmtend="2456" sqlhandle="0x03000600db082c08ba823f00d99e00000100000000000000">
SELECT TOP 1
Col1, Col2, Col3
FROM The2ndTable
INNER JOIN [dbo].[TheOneTable] ON [dbo].[TheOneTable].[LinkBetweenOneAndTwoId]=[The2ndTable].[LinkBetweenOneAndTwoId]
WHERE [dbo].[TheOneTable].ZId= #ActivityId and
[TheOneTable].[n
</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 6 Object Id = 137103579] </inputbuf>
</process>
<process id="process6334088" taskpriority="0" logused="0" waitresource="KEY: 6:72057594098810880 (ffffffffffff)" waittime="5668" ownerId="24229434" transactionname="SELECT" lasttranstarted="2011-05-17T03:29:16.587" XDES="0x17ea9ac90" lockMode="RangeS-S" schedulerid="12" kpid="5104" status="suspended" spid="86" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2011-05-17T03:29:16.587" lastbatchcompleted="2011-05-17T03:29:16.587" clientapp=".Net SqlClient Data Provider" hostname="SOMEHOST" hostpid="28820" loginname="someloginname" isolationlevel="serializable (4)" xactid="24229434" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="GetOneRowEByFId" line="11" stmtstart="260" stmtend="2456" sqlhandle="0x03000600db082c08ba823f00d99e00000100000000000000">
SELECT TOP 1
Col1, Col2, Col3
FROM The2ndTable
INNER JOIN [dbo].[TheOneTable] ON [dbo].[TheOneTable].[LinkBetweenOneAndTwoId]=[The2ndTable].[LinkBetweenOneAndTwoId]
WHERE [dbo].[TheOneTable].ZId= #ActivityId and
[TheOneTable].[n</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 6 Object Id = 137103579] </inputbuf>
</process>
<process id="process8808e08" taskpriority="0" logused="0" waitresource="KEY: 6:72057594098810880 (ffffffffffff)" waittime="6652" ownerId="24217112" transactionname="SELECT" lasttranstarted="2011-05-17T03:29:15.610" XDES="0x833b5ca0" lockMode="RangeS-S" schedulerid="1" kpid="19752" status="suspended" spid="89" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2011-05-17T03:29:15.610" lastbatchcompleted="2011-05-17T03:29:15.610" clientapp=".Net SqlClient Data Provider" hostname="SOMEHOST" hostpid="28820" loginname="someloginname" isolationlevel="serializable (4)" xactid="24217112" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="GetOneRowEByFId" line="11" stmtstart="260" stmtend="2456" sqlhandle="0x03000600db082c08ba823f00d99e00000100000000000000">
SELECT TOP 1
Col1, Col2, Col3
FROM The2ndTable
INNER JOIN [dbo].[TheOneTable] ON [dbo].[TheOneTable].[LinkBetweenOneAndTwoId]=[The2ndTable].[LinkBetweenOneAndTwoId]
WHERE [dbo].[TheOneTable].ZId= #ActivityId and
[TheOneTable].[n
</frame>
</executionStack>
<inputbuf>
Proc [Database Id = 6 Object Id = 137103579] </inputbuf>
</process>
<process id="process5c08988" taskpriority="0" logused="1644" waitresource="KEY: 6:72057594098810880 (91a0638558d2)" waittime="4889" ownerId="24214248" transactionname="user_transaction" lasttranstarted="2011-05-17T03:29:15.327" XDES="0x186609470" lockMode="RangeI-N" schedulerid="9" kpid="9000" status="suspended" spid="102" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2011-05-17T03:29:15.330" lastbatchcompleted="2011-05-17T03:29:15.330" clientapp=".Net SqlClient Data Provider" hostname="SOMEHOST" hostpid="28820" loginname="someloginname" isolationlevel="serializable (4)" xactid="24214248" currentdb="6" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="InsertIntoTheOneTable" line="25" stmtstart="1334" stmtend="2608" sqlhandle="0x03000600bbbacb5d25883f00d99e00000100000000000000">
INSERT INTO [dbo].[TheOneTable] (Some,Col,Here)
VALUES (#some,#col,#here) </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 6 Object Id = 1573632699] </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594098810880" dbid="6" objectname="TheOneTable" indexname="PK_TheOneTable" id="lock6b17a00" mode="RangeI-N" associatedObjectId="72057594098810880">
<owner-list />
<waiter-list>
<waiter id="process722c508" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594098810880" dbid="6" objectname="TheOneTable" indexname="PK_TheOneTable" id="lock6b17a00" mode="RangeI-N" associatedObjectId="72057594098810880">
<owner-list />
<waiter-list>
<waiter id="process7185048" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594098810880" dbid="6" objectname="TheOneTable" indexname="PK_TheOneTable" id="lock6b17a00" mode="RangeI-N" associatedObjectId="72057594098810880">
<owner-list />
<waiter-list>
<waiter id="process7223048" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594098810880" dbid="6" objectname="TheOneTable" indexname="PK_TheOneTable" id="lock6b17a00" mode="RangeI-N" associatedObjectId="72057594098810880">
<owner-list />
<waiter-list>
<waiter id="process6334088" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594098810880" dbid="6" objectname="TheOneTable" indexname="PK_TheOneTable" id="lock6b17a00" mode="RangeI-N" associatedObjectId="72057594098810880">
<owner-list>
<owner id="process5c08988" mode="RangeI-N" />
</owner-list>
<waiter-list>
<waiter id="process8808e08" mode="RangeS-S" requestType="wait" />
</waiter-list>
</keylock>
<keylock hobtid="72057594098810880" dbid="6" objectname="TheOneTable" indexname="PK_TheOneTable" id="lock6372e80" mode="RangeS-S" associatedObjectId="72057594098810880">
<owner-list>
<owner id="process7223048" mode="RangeS-S" />
<owner id="process6334088" mode="RangeS-S" />
</owner-list>
<waiter-list>
<waiter id="process5c08988" mode="RangeI-N" requestType="wait" />
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
In the context of locking, tables and their related indexes are separate entities. At times, dead locking happens between a table and its index, rather than between two separate tables.
The problem is most likely when a lock is aquired on an index and then another lock is aquired on the related table (i.e. bar) to do the data lookup. During the insert, this will happen in the opposite order. First, the table (i.e. bar) is locked and updated, then indexes are locked.
select foo
from bar
where #someId = 0 OR SomeId = #someId
Do you have/can you add a covering index (to help with the select) that contains both the SomeId and foo ? This way you'll avoid the lookup altogether and stop the problem from occuring.
Can you post the query plans rather than deadlock frames?
Would you mind trying some alternate criteria? I've been playing with this method lately (only I use NULLs not 0 to mean all values):
SET #yId = NullIf(#yId, 0);
SET #xId = NullIf(#xId, 0);
...
WHERE
#yId BETWEEN Coalesce(#yId, 0) AND Coalesce(#yId, 2147483647)
AND #xId BETWEEN Coalesce(#xId, 0) AND Coalesce(#xId, 2147483647)
Or you could use your zeroes intact:
WHERE
#yId BETWEEN #yId AND Coalesce(NullIf(#yId, 0), 2147483647)
AND #xId BETWEEN #xId AND Coalesce(NullIf(#xId, 0), 2147483647)
Thinking about this a little more... just to review, deadlocks only occur because of conflicting resource acquisition order. A resource is not just a table but rows, extents, pages, etc. If two queries are being submitted at once that initially acquire a smaller granularity lock, then escalate their locks to a something that overlaps the smaller lock the other process has, then you get a deadlock.
So, is there any way you can either acquire the larger lock earlier, avoid acquiring the larger conflicting lock, or change the resource acquisition order?
You could experiment with using WITH (TABLOCKX) which sounds horrible, but if your #yId or #xId is 0 thus making you select all rows, you're going to need the whole table anyway.
Have you also considered trying OPTION (MAXDOP 1) just to see if it helps? Theoretically, having multiple streams for the same data request could increase the likelihood of conflicting locks being acquired simultaneously.
Does the table have a clustered index? If not, add it, and if so, is it being used or can you force it to be used? This potentially could make the queries access the table in a different way, preventing the deadlock.
Post your comments and I'll see if any more ideas come up based on your responses.