I am reviewing my ASP.NET application and found that the deadlock issue occurs quite often (twice and more in a week). I am seeking for help to found out why deadlock happen and how to solve it.
Background: a warehouse application to deal with user requests.
Request_Table
: stores request item and will be remove if processed.
Requestor_Division* | Requestor_Section* | Item_Division* | Item_Code* | Req_Qty | Status |
---|---|---|---|---|---|
Division A | Section 1 | Division Z | Item A | 1 | Requested |
Division A | Section 1 | Division Z | Item B | 1 | Requested |
Division A | Section 1 | Division Z | Item C | 1 | Requested |
Division A | Section 1 | Division Z | Item D | 1 | Requested |
Division B | Section 2 | Division Z | Item A | 1 | Requested |
Division B | Section 2 | Division Z | Item B | 1 | Requested |
Division B | Section 2 | Division Z | Item C | 1 | Requested |
(*) is the primary key column.
Note: one division may have one or many sections.
And here is the deadlock graph:
<deadlock-list>
<deadlock victim="process26ff73804e8">
<process-list>
<process id="process26ff73804e8" taskpriority="0" logused="0" waitresource="KEY: 14:72057594130399232 (93f4f9fceb1e)" waittime="4900" ownerId="7888090087" transactionname="SELECT" lasttranstarted="2023-08-14T11:07:33.263" XDES="0x2741db0f270" lockMode="RangeS-S" schedulerid="6" kpid="10376" status="suspended" spid="872" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2023-08-14T11:07:33.260" lastbatchcompleted="2023-08-14T11:07:33.257" lastattention="1900-01-01T00:00:00.257" clientapp="LAMSM4, XXXX" hostname="VM-XXXSVR123" hostpid="6048" loginname="XXX_DBUSER" isolationlevel="serializable (4)" xactid="7888090087" currentdb="14" currentdbname="XXXXX" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="XXXXX.dbo.usp_XXXXX_GET_XXXXX_Request_Order_List" line="22" stmtstart="920" stmtend="4948" sqlhandle="0x03000e00745a5a75ce99f8004ab0000001000000000000000000000000000000000000000000000000000000">
SELECT
Item_Division = XXXX_Request_Table.Item_Division,
Requestor_Division = XXXX_Request_Table.Requestor_Division,
Requestor_Div_Name = Division.Div_EngName,
Requestor_Section = XXXX_Request_Table.Requestor_Section,
Requestor_Sec_Name = Section.Section_Name,
Status = XXXX_Request_Table.Status,
Status_Desc = CASE XXXX_Request_Table.Status
WHEN 0 THEN 'Cancelled'
WHEN 1 THEN 'Pending'
WHEN 2 THEN 'Requested'
WHEN 3 THEN 'Acknowledged'
WHEN 4 THEN 'Processing'
WHEN 5 THEN 'Completed'
WHEN 6 THEN 'Back Order'
END,
Is_Urgent = ISNULL(XXXX_Request_Table.Is_Urgent,0),
Requested_DT = MIN(XXXX_Request_Table.Requested_DT),
Processing_DT = MIN(XXXX_Request_Table.Processing_DT),
Print_Slip_DT = MIN(XXXX_Request_Table.Print_Slip_DT),
Picking_No = XXXX_Request_Table.Picking_No,
No_Of_Item = COUNT(XXXX_Request_Table.Item_Code)
FROM
XXXX_Request_Table
JOIN @tbl_Status a ON XXXX_Request_Table.Status = a.Status
JOIN Division ON XXXX_Request_Table.Request_Division = Division </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 14 Object Id = 1968855668] </inputbuf>
</process>
<process id="process270db23b848" taskpriority="0" logused="210268" waitresource="KEY: 14:72057594130399232 (2dd0ed242191)" waittime="2471" ownerId="7888086305" transactionname="user_transaction" lasttranstarted="2023-08-14T11:07:32.370" XDES="0x273b7864bd0" lockMode="X" schedulerid="6" kpid="7668" status="suspended" spid="1599" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2023-08-14T11:07:35.687" lastbatchcompleted="2023-08-14T11:07:35.693" lastattention="1900-01-01T00:00:00.693" clientapp="FUNGPY, XXXXX" hostname="VM-XXXSVR123" hostpid="6048" loginname="XXX_DBUSER" isolationlevel="serializable (4)" xactid="7888086305" currentdb="14" currentdbname="XXXX" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
<executionStack>
<frame procname="XXXXX.dbo.usp_XXXXX_UPD_XXXXX_Request" line="281" stmtstart="19768" stmtend="20494" sqlhandle="0x03000e00ad7e4e76f2a0f8004ab0000001000000000000000000000000000000000000000000000000000000">
UPDATE XXXX_Request_Table
SET
Delivered_Qty = ISNULL(Delivered_Qty, 0) + ISNULL(@Delivered_Qty, 0),
WS_Name = @WS_Name,
User_Code = @User_Code,
LastUpdate = GETDATE()
WHERE
Requestor_Division = @Requestor_Division
AND Requestor_Section = @Requestor_Section
AND Item_Division =@Item_Division
AND Item_Code = @Item_Cod </frame>
</executionStack>
<inputbuf>
Proc [Database Id = 14 Object Id = 1984855725] </inputbuf>
</process>
</process-list>
<resource-list>
<keylock hobtid="72057594130399232" dbid="14" objectname="XXXXX.dbo.XXXX_Request" indexname="PK_XXXXX_Request" id="lock273a1137f00" mode="X" associatedObjectId="72057594130399232">
<owner-list>
<owner id="process270db23b848" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process26ff73804e8" mode="RangeS-S" requestType="wait"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594130399232" dbid="14" objectname="XXXXX.dbo.XXXX_Request" indexname="PK_XXXX_Request" id="lock275582dab80" mode="RangeS-S" associatedObjectId="72057594130399232">
<owner-list>
<owner id="process26ff73804e8" mode="RangeS-S"/>
</owner-list>
<waiter-list>
<waiter id="process270db23b848" mode="X" requestType="convert"/>
</waiter-list>
</keylock>
</resource-list>
</deadlock>
</deadlock-list>
After studying the log, here are my findings:
Deadlock victim process (getting request item list):
SELECT *
FROM request_table
WHERE Requestor_Division = 'Division B'
AND Requestor_Section = 'Section 2'
AND Item_Division = 'Division Z'
Another process(update request item status for processing):
BEGIN TRAN
for loop item in Requestor Division A and Section 1:
UPDATE status = 'Acknowledged'
FROM request_table
WHERE Requestor_Division = 'Division A'
AND Requestor_Section = 'Section 1'
AND Item_Division = 'Division Z'
AND Item_Code = 'xxxx'
COMMIT TRAN
I am wondering two if processes are reading and updating different records and why it would be a deadlock.