SQL server 死锁图解释

Posted

技术标签:

【中文标题】SQL server 死锁图解释【英文标题】:SQL server deadlock graph explained 【发布时间】:2015-04-02 12:54:45 【问题描述】:

我正在测试一个最终同时执行以下存储过程的场景或重复请求

ALTER PROCEDURE [dbo].[clear_class]( @classID [int])
AS
BEGIN 

  DELETE FROM [dbo].[class_action]
  WHERE class_id=@classID;

  DELETE FROM [dbo].[page_item_image] 
  WHERE class_id=@classID;

  DELETE pis
  FROM [dbo].[page_item_spec] as pis 
  JOIN page_item AS pit ON (pis.pi_id=pit.pi_id AND pit.pi_owner=@classID) 

  DELETE FROM [dbo].[page_item] 
  WHERE pi_owner=@classID;

  DELETE FROM [dbo].[page] 
  WHERE page_owner=@classID;

  DELETE FROM [dbo].[image] 
  WHERE img_owner=@classID;

  DELETE FROM [dbo].[class_style] 
  WHERE class_id=@classID;

  DELETE FROM [dbo].[style] 
  WHERE sty_owner=@classID;

  DELETE FROM [dbo].[class_text] 
  WHERE class_id=@classID;

  DELETE FROM [dbo].[text] 
  WHERE text_owner=@classID;

  DELETE FROM [dbo].[action] 
  WHERE act_owner=@classID;
END

我得到死锁异常。 死锁图如下:

<deadlock-list>
 <deadlock victim="process2f7f61848">
  <process-list>
   <process id="process2f7f61848" taskpriority="0" logused="55572" waitresource="KEY: 5:72057594104315904 (81110f5858a7)" waittime="2947" ownerId="161655" transactionname="user_transaction" lasttranstarted="2015-04-02T15:36:12.427" XDES="0x2effb83b0" lockMode="U" schedulerid="1" kpid="9908" status="suspended" spid="59" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-04-02T15:36:12.427" lastbatchcompleted="2015-04-02T15:36:12.417" lastattention="1900-01-01T00:00:00.417" clientapp="EntityFramework" hostname="MVERG" hostpid="8084" loginname="menelaos" isolationlevel="read committed (2)" xactid="161655" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="db.dbo.p_clear_class" line="15" stmtstart="722" stmtend="874" sqlhandle="0x03000500dfae3842b1f7fa006ea4000001000000000000000000000000000000000000000000000000000000">
DELETE FROM [dbo].[page_item_image] with(rowlock)
    WHERE class_id=@classI     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 5 Object Id = 1111011039]    </inputbuf>
   </process>
   <process id="process2f53ff468" taskpriority="0" logused="425956" waitresource="KEY: 5:72057594104119296 (cc50c8bdfc5d)" waittime="2921" ownerId="161454" transactionname="user_transaction" lasttranstarted="2015-04-02T15:36:12.303" XDES="0x2eed31000" lockMode="S" schedulerid="1" kpid="8516" status="suspended" spid="61" sbid="2" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-04-02T15:36:12.303" lastbatchcompleted="2015-04-02T15:36:12.303" lastattention="1900-01-01T00:00:00.303" clientapp="EntityFramework" hostname="MVERG" hostpid="8084" loginname="menelaos" isolationlevel="read committed (2)" xactid="161454" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="db.dbo.p_clear_class" line="40" stmtstart="2108" stmtend="2244" sqlhandle="0x03000500dfae3842b1f7fa006ea4000001000000000000000000000000000000000000000000000000000000">
DELETE FROM [dbo].[text] with(rowlock)
    WHERE text_owner=@classI     </frame>
    </executionStack>
    <inputbuf>
Proc [Database Id = 5 Object Id = 1111011039]    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057594104315904" dbid="5" objectname="db.dbo.page_item_image" indexname="PK_page_item_image" id="lock2ef2e4900" mode="X" associatedObjectId="72057594104315904">
    <owner-list>
     <owner id="process2f53ff468" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process2f7f61848" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594104119296" dbid="5" objectname="db.dbo.page_item" indexname="PK_page_item" id="lock2f02ee900" mode="X" associatedObjectId="72057594104119296">
    <owner-list>
     <owner id="process2f7f61848" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process2f53ff468" mode="S" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>

我看到问题与锁定模式有关,表是锁定模式's'并且需要锁定模式'x'但是其他进程已经用'u'锁定了表......

我该怎么做才能解决这个僵局?是因为执行顺序吗? IX 锁是否可以解决任何问题,如果可以,我该如何设置?

【问题讨论】:

任意表之间是否有外键,比如text表和page_item_image表之间? 它们之间没有直接的约束。 'Text' 表很受欢迎,因为它被多个表使用,而不是 page_item_image。 page_item和page_item_image之间有外键吗? 【参考方案1】:

我不是 100% 确定,但你可以试试这个,看看它是否有帮助。

目前所有删除语句都在一个批次中执行。因此,如果删除语句获得ExclusiveUpdate 锁,则如果它需要访问相同的资源,则以下语句将被阻塞。

创建两个新过程来执行删除语句,分别在它们自己的批处理中。一个用于标准的单表删除语句,一个用于通过连接两个表进行的删除(否则一个 proc 应该就足够了)

删除数据程序

程序一

此过程一次从单个表中删除数据。

CREATE PROCEDURE dbo.usp_Delete_Class 
 @TableName SYSNAME
,@classID INT
AS
BEGIN
  SET NOCOUNT ON;
  DECLARE @Sql NVARCHAR(MAX);

  BEGIN TRANSACTION;

SET @Sql = N'DELETE FROM [dbo].' + QUOTENAME(@TableName)
         + N' WHERE class_id = @classID; '   

Exec sp_executesql @Sql  
                  ,N'@classID INT'
                  ,@classID

 IF @@ERROR = 0 
      COMMIT TRANSACTION;
 ELSE 
      ROLLBACK TRANSACTION;
END

程序 2

通过连接两个表来删除数据

CREATE PROCEDURE dbo.usp_Delete_Class_page_item_spec
 @classID INT
AS
BEGIN
  SET NOCOUNT ON;

  BEGIN TRANSACTION;

  DELETE pis
  FROM [dbo].[page_item_spec] as pis 
  JOIN page_item AS pit ON (pis.pi_id=pit.pi_id AND pit.pi_owner=@classID) 

 IF @@ERROR = 0 
      COMMIT TRANSACTION;
 ELSE 
      ROLLBACK TRANSACTION;
END

主程序

ALTER PROCEDURE [dbo].[clear_class]
  @classID INT
AS
BEGIN 
   SET NOCOUNT ON;

  Exec dbo.usp_Delete_Class 'class_action' , @classID

  Exec dbo.usp_Delete_Class 'page_item_image' , @classID

  Exec dbo.usp_Delete_Class_page_item_spec  @classID

  Exec dbo.usp_Delete_Class 'page_item' , @classID

  Exec dbo.usp_Delete_Class 'page' , @classID

  Exec dbo.usp_Delete_Class 'image' , @classID

  Exec dbo.usp_Delete_Class 'Class_Style' , @classID

  Exec dbo.usp_Delete_Class 'Style' , @classID

  Exec dbo.usp_Delete_Class 'Class_Text' , @classID

  Exec dbo.usp_Delete_Class 'Text' , @classID

  Exec dbo.usp_Delete_Class 'Action' , @classID

END

【讨论】:

不幸的是现在它在Exec dbo.usp_Delete_Class 处死锁:-(

以上是关于SQL server 死锁图解释的主要内容,如果未能解决你的问题,请参考以下文章

了解sql server的死锁图

SQL Server Profiler 中的死锁图显示同一集群键上的互锁

Sql server 死锁排查

sql server 死锁排查

SQL Server 上的死锁跟踪

UPDATE 上的 SQL Server 死锁