SQL Server 并发删除/插入应用程序

3 sql-server delete insert concurrency

我们如何在并行的多线程环境中删除然后插入行,同时避免死锁?应用UPDLOCK和后,我仍然收到僵局SERIALIZABLE。请参阅下面的死锁错误。

资源:

我有一个 C#/ASP 应用程序在并发环境中运行两个不同的连接,尝试删除并稍后为一个人插入数据。我听说应用程序的行为有所不同。

我试过这个:

connection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
Run Code Online (Sandbox Code Playgroud)

connection.BeginTransaction(System.Data.IsolationLevel.Serializable))
Run Code Online (Sandbox Code Playgroud)

上存在非聚集索引HeaderId,相同的索引Headerid可以在表中出现多次。

<event name="xml_deadlock_report" package="sqlserver" timestamp="2017-10-10T07:10:41.524Z">
  <data name="xml_report">
    <value>
      <deadlock>
        <victim-list>
          <victimProcess id="process3e7eb2188" />
        </victim-list>
        <process-list>
          <process id="process3e7eb2188" taskpriority="0" logused="26140" waitresource="KEY: 11:72057594039304192 (32fb2d1e9782)" waittime="3176" ownerId="2548574" transactionname="user_transaction" lasttranstarted="2017-10-10T00:10:38.313" XDES="0x3e7f223a8" lockMode="RangeS-U" schedulerid="8" kpid="18256" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2017-10-10T00:10:38.323" lastbatchcompleted="2017-10-10T00:10:38.320" lastattention="1900-01-01T00:00:00.320" clientapp=".Net SqlClient Data Provider" hostname="JOHN-SMITH" hostpid="12976" loginname="johnsmith" isolationlevel="serializable (4)" xactid="2548574" currentdb="11" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
              <frame procname="adhoc" line="2" stmtstart="78" stmtend="496" sqlhandle="0x020000008f7940276a944bab809d15d2d911582332671d9f0000000000000000000000000000000000000000">
IF EXISTS 
                (
                    select * from [dbo].[FinanceDetail] trd WITH (UPDLOCK, SERIALIZABLE)
                    where trd.HeaderId = @HeaderId
                )    </frame>
              <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
(@HeaderId bigint)   
                IF EXISTS 
                (
                    select * from [dbo].[FinanceDetail] trd WITH (UPDLOCK, SERIALIZABLE)
                    where trd.HeaderId = @HeaderId
                )
                DELETE from dbo.FinanceDetail
                where HeaderId = @HeaderId   </inputbuf>
          </process>
          <process id="process3f4792188" taskpriority="0" logused="33252" waitresource="KEY: 11:72057594039304192 (ffff51c3d6d0)" waittime="3176" ownerId="2548594" transactionname="user_transaction" lasttranstarted="2017-10-10T00:10:38.340" XDES="0x3e50a4d08" lockMode="RangeS-U" schedulerid="2" kpid="12624" status="suspended" spid="59" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2017-10-10T00:10:38.340" lastbatchcompleted="2017-10-10T00:10:38.340" lastattention="1900-01-01T00:00:00.340" clientapp=".Net SqlClient Data Provider" hostname="JOHN-SMITH" hostpid="12976" loginname="johnsmith" isolationlevel="serializable (4)" xactid="2548594" currentdb="11" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
              <frame procname="adhoc" line="7" stmtstart="498" stmtend="646" sqlhandle="0x020000008f7940276a944bab809d15d2d911582332671d9f0000000000000000000000000000000000000000">
DELETE from dbo.FinanceDetail
                where HeaderId = @HeaderI    </frame>
              <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
(@HeaderId bigint)   
                IF EXISTS 
                (
                    select * from [dbo].[FinanceDetail] trd WITH (UPDLOCK, SERIALIZABLE)
                    where trd.HeaderId = @HeaderId
                )
                DELETE from dbo.FinanceDetail
                where HeaderId = @HeaderId   </inputbuf>
          </process>
          <process id="process3e7eb2558" taskpriority="0" logused="35336" waitresource="KEY: 11:72057594039304192 (ffff51c3d6d0)" waittime="3199" ownerId="2548590" transactionname="user_transaction" lasttranstarted="2017-10-10T00:10:38.320" XDES="0x3e7f22d28" lockMode="RangeS-U" schedulerid="8" kpid="12480" status="suspended" spid="60" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2017-10-10T00:10:38.323" lastbatchcompleted="2017-10-10T00:10:38.323" lastattention="1900-01-01T00:00:00.323" clientapp=".Net SqlClient Data Provider" hostname="JOHN-SMITH" hostpid="12976" loginname="johnsmith" isolationlevel="serializable (4)" xactid="2548590" currentdb="11" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
            <executionStack>
              <frame procname="adhoc" line="2" stmtstart="78" stmtend="496" sqlhandle="0x020000008f7940276a944bab809d15d2d911582332671d9f0000000000000000000000000000000000000000">
IF EXISTS 
                (
                    select * from [dbo].[FinanceDetail] trd WITH (UPDLOCK, SERIALIZABLE)
                    where trd.HeaderId = @HeaderId
                )    </frame>
              <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
(@HeaderId bigint)   
                IF EXISTS 
                (
                    select * from [dbo].[FinanceDetail] trd WITH (UPDLOCK, SERIALIZABLE)
                    where trd.HeaderId = @HeaderId
                )
                DELETE from dbo.FinanceDetail
                where HeaderId = @HeaderId   </inputbuf>
          </process>
        </process-list>
        <resource-list>
          <keylock hobtid="72057594039304192" dbid="11" objectname="TaxReturn.dbo.FinanceDetail" indexname="AK_FinanceDetail_HeaderId" id="lock3e4c12e80" mode="RangeX-X" associatedObjectId="72057594039304192">
            <owner-list>
              <owner id="process3f4792188" mode="RangeX-X" />
            </owner-list>
            <waiter-list>
              <waiter id="process3e7eb2188" mode="RangeS-U" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057594039304192" dbid="11" objectname="TaxReturn.dbo.FinanceDetail" indexname="AK_FinanceDetail_HeaderId" id="lock3e4c57700" mode="RangeS-U" associatedObjectId="72057594039304192">
            <owner-list>
              <owner id="process3e7eb2558" mode="RangeS-U" requestType="wait" />
            </owner-list>
            <waiter-list>
              <waiter id="process3f4792188" mode="RangeS-U" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057594039304192" dbid="11" objectname="TaxReturn.dbo.FinanceDetail" indexname="AK_FinanceDetail_HeaderId" id="lock3e4c57700" mode="RangeS-U" associatedObjectId="72057594039304192">
            <owner-list>
              <owner id="process3e7eb2188" mode="RangeS-U" />
            </owner-list>
            <waiter-list>
              <waiter id="process3e7eb2558" mode="RangeS-U" requestType="wait" />
            </waiter-list>
          </keylock>
        </resource-list>
      </deadlock>
    </value>
  </data>
</event>
Run Code Online (Sandbox Code Playgroud)

@HeaderIdbigint在SQL,long在C#。执行计划有seek,没有隐式转换,FinanceDetail.HeaderId = Scalar Operator(@HeaderId)

Bre*_*zar 13

您上面显示的唯一查询似乎是这个,重复了几次:

IF EXISTS 
                (
                    select * from [dbo].[FinanceDetail] trd WITH (UPDLOCK, SERIALIZABLE)
                    where trd.HeaderId = @HeaderId
                )
                DELETE from dbo.FinanceDetail
                where HeaderId = @HeaderId  
Run Code Online (Sandbox Code Playgroud)

为避免死锁,请将您的查询简化为:

                DELETE from dbo.FinanceDetail
                where HeaderId = @HeaderId  
Run Code Online (Sandbox Code Playgroud)

如果您只是要删除行,则不需要检查行是否存在,并且不需要任何锁定提示来单独运行删除语句。

如果您尝试删除不存在的记录,您将不会收到错误消息。它只会报告受影响的 0 行,您可以使用@@ROWCOUNT.