PLS。我们一直在生产数据库上获得很多锁定,这些数据库最近见证了大量增加的流量。我们使用IdeaBlade进行大部分数据访问。
我使用Sql Profiler获得了以下跟踪:
deadlock victim="process84af28"
resource-list
keylock hobtid="72057594096451584" dbid="6" objectname="cpc_db.dbo.Prefix_ChildTableName" indexname="PK_Prefix_ChildTableName" id="lock45982ac0" mode="X" associatedObjectId="72057594096451584"
owner-list
owner id="processb852e8" mode="X"
owner-list
waiter-list
waiter id="process84af28" mode="S" requestType="wait"
waiter id="processb855b8" mode="RangeS-U" requestType="wait"
waiter-list
keylock
keylock hobtid="72057594096451584" dbid="6" objectname="cpc_db.dbo.Prefix_ChildTableName" indexname="PK_Prefix_ChildTableName" id="lock513c3bc0" mode="RangeS-U" associatedObjectId="72057594096451584"
owner-list
owner id="processb855b8" mode="RangeS-U"
owner-list
waiter-list
waiter id="processb852e8" mode="RangeS-U" requestType="wait"
waiter-list
keylock
resource-list
deadlock
想点什么?
我不是DBA,但这条痕迹似乎表明:
子表中某行上具有独占锁X的进程正在尝试获取同一资源上的选择 - 更新锁(似乎没有意义)
另一个具有Select-Update锁定的进程仍在尝试获取Select-Update锁定
澄清任何人?
我们如何最小化或消除死锁?
答案 0 :(得分:1)
首先要注意的事情:
您正在使用serializable transactions这一最严格的悲观锁定形式。有可能,你不需要这个(我们知道你使用的是可序列化的事务,因为KEY锁只适用于这个隔离级别)。正如Remus上面提到的那样,你最有可能在这里考虑其他选择。
上面的输出似乎被截断了一些,你应该有一个名为process-list的部分,其中包含将过程信息映射到spid和查询的信息
从上面的输出中可以看出:
processb852e8 owns an exclusive lock on index "cpc_db.dbo.Prefix_ChildTableName.PK_Prefix_ChildTableName"
process84af28 is waiting for a shared KEY lock
processb855b8 is also waiting for a Shared Range-Update KEY lock
processb855b8 owns Shared Range-Update lock on index "cpc_db.dbo.Prefix_ChildTableName.PK_Prefix_ChildTableName" (the same index)
processb852e8 is waiting on a Shared Range-Update KEY lock
独占锁是某种类型的写(即更新,删除,插入),RangeS-U锁可能是更新,但没有看到映射信息就无法判断。
如果你拥有所有内容,Bart Duncan有几篇关于破译跟踪输出的好文章,请参阅part 1和part 2。您还可以查看一般here的并发和脚本概述。
答案 1 :(得分:0)
mode="RangeS-U"
范围锁定?停止使用高事务隔离级别。坚持阅读承诺。如果您使用CLR TransactionScope对象,请使用Read Commited隔离(默认情况下,它们使用Seralizable,yuck)。尝试在数据库上启用read committed snapshot isolation。请参阅Using Snapshot Isolation。
答案 2 :(得分:0)
owner id="processb855b8" mode="RangeS-U"
这似乎锁定了一组行。 它等待一行由process84af28重新定义, 正在等待一行由processb852e8发布 等待第一个进程释放一行。
SQLServer通过在中间杀死进程来解决死锁,允许其他两个进程完成。
你应该看看你的隔离级别。最佳做法是使用最低价 “选择”多行时的可用锁定级别。 如果您很可能更新当前事务中的行,则只在“选择”行上使用更高级别。
永远不要在等待外部服务或用户操作时锁定行。
答案 3 :(得分:0)
我自己用不同的产品(不是IdeaBlade)看到了这个死锁问题。根据我的经验,这不是数据库问题;软件与数据库通信可能存在问题。
我的问题在于与数据库通信的组件的配置。
第一次,COM +默认为SERIALIZABLE,必须配置为默认为READ COMMITTED。
第二次,COM +到.NET互操作条件导致数据库连接默认为SERIALIZABLE。
对我们来说,一个快速而肮脏的解决方案是在SQL命令前加上“SET TRANSACTION ISOLATION LEVEL READ COMMITTED”来覆盖SERIALIZABLE直到核心问题得到解决。