Search code examples
sql-serversql-server-2012database-deadlocks

Deadlock between delete and update statement in SQL Server 2012


I'm facing a problem in a database between 2 stored procedures, one trying to update and the other wants to delete some huge amount of data.

My Offer table contains 50 million rows (I know not a good practice, I'm purging the data).

The table contains an incremental ID (not offer_id) which is the primary key with a clustered index on it.

xml_deadlock_report :

  <event name="xml_deadlock_report" package="sqlserver" timestamp="2018-01-02T00:56:16.360Z">
    <data name="xml_report">
        <type name="xml" package="package0" />
        <value>
            <deadlock>
                <victim-list>
                    <victimProcess id="process3697498" />
                </victim-list>
                <process-list>
                    <process id="process3697498" taskpriority="0" logused="127362200" waitresource="PAGE: 9:1:99977592 " waittime="6212" ownerId="32514985656" transactionname="DELETE" lasttranstarted="2018-01-02T01:55:56.853" XDES="0x902e53ed28" lockMode="IX" schedulerid="5" kpid="10104" status="suspended" spid="155" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2018-01-02T00:00:02.427" lastbatchcompleted="2018-01-02T00:00:02.427" lastattention="1900-01-01T00:00:00.427" clientapp="SQLAgent - TSQL JobStep (Job 0xAF5CC7B9127279438B52607063734954 : Step 1)" hostname="HB01-BOSQL-CL02" hostpid="5008" loginname="RUEDUCOMMERCE\hicham.boutaleb" isolationlevel="read committed (2)" xactid="32514985656" currentdb="9" lockTimeout="4294967295" clientoption1="671088928" clientoption2="128056">
                        <executionStack>
                            <frame procname="EchangesDb.dbo.PurgeGM2" line="433" stmtstart="57518" stmtend="57750" sqlhandle="0x03000900c9c6d33469f20e0158a8000001000000000000000000000000000000000000000000000000000000">
DELETE 
                TOP (100000)
                OFFER
            WHERE
                ID IN (SELECT ID FROM #OFFERSTODELETE)
             OPTION(MAXDOP 1)    
                            </frame>
                            <frame procname="adhoc" line="1" sqlhandle="0x010009008b23cd0690ffbc006500000000000000000000000000000000000000000000000000000000000000">
Exec PurgeGM2    </frame>
                        </executionStack>
                        <inputbuf>
Exec PurgeGM2   </inputbuf>
                    </process>
                    <process id="process5b230c8" taskpriority="0" logused="183626528" waitresource="PAGE: 9:1:99056248 " waittime="2010" ownerId="32514934129" transactionname="user_transaction" lasttranstarted="2018-01-02T01:55:46.243" XDES="0xd0e49f16c0" lockMode="U" schedulerid="15" kpid="10684" status="suspended" spid="128" sbid="0" ecid="22" priority="0" trancount="0" lastbatchstarted="2018-01-02T01:55:46.240" lastbatchcompleted="2018-01-02T01:55:46.240" lastattention="1900-01-01T00:00:00.240" clientapp=".Net SqlClient Data Provider" hostname="HB01-BIZTALK01" hostpid="2620" isolationlevel="read committed (2)" xactid="32514934129" currentdb="9" lockTimeout="4294967295" clientoption1="673317152" clientoption2="128056">
                        <executionStack>
                            <frame procname="EchangesDb.dbo.offer_insert_diff" line="183" stmtstart="8450" stmtend="8780" sqlhandle="0x0300090048642c329947700146a8000001000000000000000000000000000000000000000000000000000000">
UPDATE o
            SET tc_process_status = 0
            FROM [dbo].[offer] AS o WITH(NOLOCK)
            INNER JOIN Temp_OffersToMove AS t WITH(NOLOCK) ON (o.offer_id = t.offer_id)    </frame>
                        </executionStack>
                        <inputbuf>
Proc [Database Id = 9 Object Id = 841770056]   
                        </inputbuf>
                    </process>
                </process-list>
                <resource-list>
                    <pagelock fileid="1" pageid="99977592" dbid="9" subresource="FULL" objectname="EchangesDb.dbo.offer" id="lock3d70957380" mode="U" associatedObjectId="72057595568062464">
                        <owner-list>
                            <owner id="process5b230c8" mode="U" />
                        </owner-list>
                        <waiter-list>
                            <waiter id="process3697498" mode="IX" requestType="wait" />
                        </waiter-list>
                    </pagelock>
                    <pagelock fileid="1" pageid="99056248" dbid="9" subresource="FULL" objectname="EchangesDb.dbo.offer" id="lock6d7712ab80" mode="IX" associatedObjectId="72057595568062464">
                        <owner-list>
                            <owner id="process3697498" mode="IX" />
                        </owner-list>
                        <waiter-list>
                            <waiter id="process5b230c8" mode="U" requestType="wait" />
                        </waiter-list>
                    </pagelock>
                </resource-list>
            </deadlock>
        </value>
    </data>
</event>

Solution

  • and thanks all for your help.

    My problem was solved by Erland's suggestions and some extra work :

    1) Reduce batch size(find the good threeshold, for me 5000).

    2) Set deadlock priorty low for the purge.

    3) Add retry for deadlocks in the purge(for 1025 errors).

    4)reduce the size of my temp table containing the rows to delete after each iteration(delete top 5000 from order by id)

    and now it works fine.

    many thnaks.