Sql server 2005 删除和更新之间的死锁

Sql server 2005 删除和更新之间的死锁,sql-server-2005,deadlock,database-deadlocks,Sql Server 2005,Deadlock,Database Deadlocks,第一个过程: <deadlock-list> <deadlock victim="process8d9798"> <process-list> <process id="process8d9798" taskpriority="0" logused="0" waitresource="PAGE: 5:1:190354" waittime="3203" ownerId="53807810" transactionname="DELETE

第一个过程:

<deadlock-list>
 <deadlock victim="process8d9798">
  <process-list>
   <process id="process8d9798" taskpriority="0" logused="0" waitresource="PAGE:
    5:1:190354" waittime="3203" ownerId="53807810" transactionname="DELETE" 
    lasttranstarted="11:29:29.153" XDES="0x3dbb518" lockMode="U" 
    schedulerid="2" kpid="1792" status="suspended" spid="57" sbid="0" ecid="1" 
    priority="0" transcount="0" lastbatchstarted="2012-09-28T11:29:29.120" 
    lastbatchcompleted="11:29:29.120" clientapp=".Net SqlClient Data Provider" 
    hostname="xxx" hostpid="4460" isolationlevel="read uncommitted (1)" 
    xactid="53807810" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" 
    clientoption2="128056">
    <executionStack>
     <frame procname="Chooser2.dbo.DeleteUserSelections" line="15" stmtstart="360"
     stmtend="464" sqlhandle="0x030005008839117bf599a500099800000100000000000000">
   DELETE UserPlanOption
    WHERE UserID = @userId     </frame>
    </executionStack>
    <inputbuf>
    </inputbuf>
   </process>

和的执行计划。

我认为死锁的原因是,UserPlanOption表的访问顺序不同,很可能是因为FamilyErid列上存在索引

您可以阅读更多关于此类问题和

避免这种死锁情况的一种可能的方法是在UPdate语句之前根据UserID列预先获取锁,如中所示

使用(UPDLOCK)从UserPlanOption中选择@userId=userId
其中UserID=@UserID

我认为死锁的原因是userplanpoption表的访问顺序不同,很可能是因为familyterid列上存在索引

您可以阅读更多关于此类问题和

避免这种死锁情况的一种可能的方法是在UPdate语句之前根据UserID列预先获取锁,如中所示

使用(UPDLOCK)从UserPlanOption中选择@userId=userId
其中UserID=@UserID

答案已更新

观察 此图基于XML死锁图:

它显示spid52在pageid=190354(UserPlanOption表)上有一个IX锁,并且在pageid=190487(来自同一个UserPlanOption表)上请求一个IU锁。我认为UserPlanOption表是一个堆表,这意味着它没有clusterd索引。另外,这意味着你的PK是非聚集的。如果要运行此查询:

SELECT i.*
FROM sys.indexes i
WHERE i.object_id = OBJECT_ID('UserPlanOption')
您将从UserPlanOption表中获得一个包含所有索引的列表(您可以发布此列表吗?)。在这种情况下,因为spid52执行更新,所以两个锁(IU和IX)都显示(在我看来)更新执行计划中可能的表/索引扫描运算符

但是,spid57在同一资源上已经有一个U锁(pageid=190487)。同一连接(spid57)请求另一页(pageid=190354)上的另一个U锁,但此资源(页)已被spid52(IX)锁定

因为(见):

[i] 现有IX和请求的U锁或

[ii]现有U锁和请求的IU锁

不兼容您有一个很好的死锁

DELETE语句的缓存计划为

注:

  • 现在,聚集索引扫描(具有并行性)操作符强制DBMS扫描UserPlanOption表中的所有行

  • 估计行数只有5行(估计已删除行数),并且*并行运算符的存在表明UserPlanOption表很大

  • 您可以看到来自SQL Server的索引建议

UPDATE语句的缓存计划为

此计划的主要问题是:速率表上的聚集索引扫描、从
[N][VAR]CHAR
(?)隐式转换为
INT
的计算标量,以及
与用户表联接之前的过滤器

解决 根据这些观察结果,解决方案应为:

[1]在\u userplanpoption\u UserID\u planpoptionId中创建索引 关于UserPlanOption(用户ID,PlanOptionID)

注1:在我的选项中,UserPlanOption表上的聚集索引扫描(DELETE)是导致此死锁的主要原因

注2:UserPlanOption在
(PlanOptionID,UserID)
列上有一个聚集索引。此索引有助于UPDATE语句(请参见PK_UserPlanOption_1上的Seek运算符:
其中…和u.ID=UserPlanOption.UserID和r.PlanOptionID=UserPlanOption.PlanOptionID和…
),但不帮助删除语句(
其中UserID=@UserID

[2]为了提高UPDATE语句的性能,您可以创建sugested索引:

-- SQL Server's suggestion
CREATE INDEX IN_Rate_FamilyTierID
ON dbo.Rate(FamilyTierID)
INCLUDE (PlanOptionID, Criterion1);
[3]要删除隐式转换,可以重写DELETE语句,如下所示:

DECLARE @Criterion1 Criterion1_datatype? 
SET @Criterion1 = dbo.GetPlanOptionAreaID_36()

UPDATE  UserPlanOption 
    SET     RateID = r.ID
    FROM    [User] u 
        LEFT JOIN Rate r ON r.FamilyTierID = u.FamilyTierID 
    WHERE   UserPlanOption.PlanOptionID NOT IN (SELECT ppo.PlanOptionID FROM 
                    @PORACPlanOptions ppo) AND
        u.ID = @userID AND u.ID = UserPlanOption.UserID AND
        r.PlanOptionID = UserPlanOption.PlanOptionID AND
        r.Criterion1 = @Criterion1
原始源代码(UPDATE语句)包含此过滤器
r.criteria=dbo.GetPlanOptionAreaID_36(…)
。此时,如果对速率表中的每一行调用该函数,则计算机标量运算符可能是另一个性能问题

这个函数是确定性函数吗

SELECT  r.IS_DETERMINISTIC, r.*
FROM    INFORMATION_SCHEMA.ROUTINES r
WHERE   r.ROUTINE_NAME='GetPlanOptionAreaID_36'

[4]我的建议是不要使用
NOLOCK
提示和/或
设置事务隔离级别READ UNCOMMITTED
。此解决方案应仅为最后一个解决方案。

答案已更新

观察 此图基于XML死锁图:

它显示spid52在pageid=190354(UserPlanOption表)上有一个IX锁,并且在pageid=190487(来自同一个UserPlanOption表)上请求一个IU锁。我认为UserPlanOption表是一个堆表,这意味着它没有clusterd索引。另外,这意味着你的PK是非聚集的。如果要运行此查询:

SELECT i.*
FROM sys.indexes i
WHERE i.object_id = OBJECT_ID('UserPlanOption')
您将从UserPlanOption表中获得一个包含所有索引的列表(您可以发布此列表吗?)。在这种情况下,因为spid52执行更新,所以两个锁(IU和IX)都显示(在我看来)更新执行计划中可能的表/索引扫描运算符

但是,spid57在同一资源上已经有一个U锁(pageid=190487)。同一连接(spid57)请求另一页(pageid=190354)上的另一个U锁,但此资源(页)已被spid52(IX)锁定

因为(见):

[i] 现有IX和请求的U锁或

[ii]现有U锁和请求的IU锁

不兼容您有一个很好的死锁

DELETE语句的缓存计划为

注:

  • 现在,聚集索引扫描(具有并行性)操作符强制DBMS扫描UserPlanOption表中的所有行

  • 估计行数只有5行(估计已删除行数),并且*并行运算符的存在表明UserPlanOption表很大

  • 您可以看到来自SQL Server的索引建议

UPDATE语句的缓存计划为

此计划的主要问题是:聚集索引扫描
-- SQL Server's suggestion
CREATE INDEX IN_Rate_FamilyTierID
ON dbo.Rate(FamilyTierID)
INCLUDE (PlanOptionID, Criterion1);
DECLARE @Criterion1 Criterion1_datatype? 
SET @Criterion1 = dbo.GetPlanOptionAreaID_36()

UPDATE  UserPlanOption 
    SET     RateID = r.ID
    FROM    [User] u 
        LEFT JOIN Rate r ON r.FamilyTierID = u.FamilyTierID 
    WHERE   UserPlanOption.PlanOptionID NOT IN (SELECT ppo.PlanOptionID FROM 
                    @PORACPlanOptions ppo) AND
        u.ID = @userID AND u.ID = UserPlanOption.UserID AND
        r.PlanOptionID = UserPlanOption.PlanOptionID AND
        r.Criterion1 = @Criterion1
SELECT  r.IS_DETERMINISTIC, r.*
FROM    INFORMATION_SCHEMA.ROUTINES r
WHERE   r.ROUTINE_NAME='GetPlanOptionAreaID_36'