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的索引建议
[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'