Why does MS SQL use exclusive locks on the entire table to update one record?

Михаил 96 Reputation points
2020-12-29T10:22:50.667+00:00

We have problems with deadlocks, judging by the logs, two requests simultaneously want to get exclusive access to the table. However, both queries change one record in the table. The error occurs at high loads. There was a lack of RAM. In this case, we use the READ COMMITTED SNAPSHOT isolation level. I understand that this isolation level is very dependent on temporary tables and if there is a lack of memory, then it will not lead to anything good. But I'm trying to explain why an exclusive table lock occurs, what is the reason?

Error log:

  <deadlock>
      <victim-list>
        <victimProcess id="process15869037088" />
      </victim-list>
      <process-list>
        <process id="process15869037088" taskpriority="0" logused="0" waitresource="OBJECT: 8:398376934:0 " waittime="3982" ownerId="1339581101" transactionname="user_transaction" lasttranstarted="2020-12-29T10:11:51.320" XDES="0x158623448e0" lockMode="S" schedulerid="4" kpid="10944" status="suspended" spid="77" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2020-12-29T10:11:51.310" lastbatchcompleted="2020-12-29T10:11:51.303" lastattention="1900-01-01T00:00:00.303" clientapp=".Net SqlClient Data Provider" hostname="KITZBUEHEL" hostpid="12192" loginname="eseddadmin" isolationlevel="serializable (4)" xactid="1339581101" currentdb="8" currentdbname="SEDD3_KIO" lockTimeout="4294967295" clientoption1="671090784" clientoption2="128056">
          <executionStack>
            <frame procname="SEDD3_KIO.dbo.spCloseApprovalRoutes" line="29" stmtstart="1286" stmtend="1796" sqlhandle="0x03000800970e9d2c3c2e3e019ba8000001000000000000000000000000000000000000000000000000000000">
    UPDATE S SET 
          State = 4, 
          CompleteDate = @Dt
          FROM WF4_Stations S inner join WF4_Routes R on RouteID = R.ID AND S.State IN (0,1,2,5) AND S.PRUZ &lt;&gt; 1 
            AND DocUID = @docUID AND R.State NOT IN(3,4,6) AND R.PRUZ &lt;&gt; 1 AND R.Type =    </frame>
          </executionStack>
          <inputbuf>
    Proc [Database Id = 8 Object Id = 748490391]   </inputbuf>
        </process>
        <process id="process1585ad4c8c8" taskpriority="0" logused="10036" waitresource="OBJECT: 8:398376934:0 " waittime="3986" ownerId="1339581866" transactionname="user_transaction" lasttranstarted="2020-12-29T10:11:51.537" XDES="0x15862341520" lockMode="X" schedulerid="3" kpid="8148" status="suspended" spid="68" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2020-12-29T10:11:51.537" lastbatchcompleted="2020-12-29T10:11:51.533" lastattention="1900-01-01T00:00:00.533" clientapp=".Net SqlClient Data Provider" hostname="KITZBUEHEL" hostpid="12192" loginname="eseddadmin" isolationlevel="read committed (2)" xactid="1339581866" currentdb="8" currentdbname="SEDD3_KIO" lockTimeout="4294967295" clientoption1="673187936" clientoption2="128056">
          <executionStack>
            <frame procname="SEDD3_KIO.dbo.spSaveApprovalSigning" line="122" stmtstart="8704" stmtend="9600" sqlhandle="0x030008000880664e1acff10087ac000001000000000000000000000000000000000000000000000000000000">
    update WF4_Routes set
          State = case when @Dt &gt;= stat.ControlDate then 4 else 3 end,
          CompleteDate = @Dt,
          UserUID = @OperatorUID,
          ModifyDate = @Dt
        from WF4_Routes R
        inner join WF4_Stages stages
          on  R.ID = @RouteID
          and stages.RouteID = R.ID
          and stages.StageType = 7
          and stages.PRUZ &lt;&gt; 1
        inner join WF4_Stations stat
          on  stat.ApprovalStageID = stages.ID
          and stat.PRUZ &lt;&gt;    </frame>
          </executionStack>
          <inputbuf>
    Proc [Database Id = 8 Object Id = 1315340296]   </inputbuf>
        </process>
      </process-list>
      <resource-list>
        <objectlock lockPartition="0" objid="398376934" subresource="FULL" dbid="8" objectname="SEDD3_KIO.dbo.WF4_Routes" id="lock151c8d7d800" mode="IX" associatedObjectId="398376934">
          <owner-list>
            <owner id="process1585ad4c8c8" mode="IX" />
            <owner id="process1585ad4c8c8" mode="X" requestType="convert" />
          </owner-list>
          <waiter-list>
            <waiter id="process15869037088" mode="S" requestType="convert" />
          </waiter-list>
        </objectlock>
        <objectlock lockPartition="0" objid="398376934" subresource="FULL" dbid="8" objectname="SEDD3_KIO.dbo.WF4_Routes" id="lock151c8d7d800" mode="IX" associatedObjectId="398376934">
          <owner-list>
            <owner id="process15869037088" mode="IS" />
            <owner id="process15869037088" mode="S" requestType="convert" />
          </owner-list>
          <waiter-list>
            <waiter id="process1585ad4c8c8" mode="X" requestType="convert" />
          </waiter-list>
        </objectlock>
      </resource-list>
    </deadlock>
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,199 questions
0 comments No comments
{count} votes

1 additional answer

Sort by: Most helpful
  1. JoyDutt 821 Reputation points
    2020-12-29T11:39:54+00:00

    Hi @Михаил
    The way to do it in SQL Server is to set an isolation level on the transaction that contains the statements that you want to execute. See this REF page (at bottom of this answer) but the general structure would look something like:

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

    BEGIN TRANSACTION;
    select * from ...
    update ...
    COMMIT TRANSACTION;
    SERIALIZABLE is the highest isolation level.

    REF: http://msdn.microsoft.com/en-us/library/ms173763.aspx

    1 person found this answer helpful.
    0 comments No comments