我已经阅读了大量关于互联网上死锁的信息,以确保我不会问一个愚蠢的问题。发生死锁的下表用作订单队列。实际上没有记录被删除,只有它们的状态发生了变化,即处理,取消,完成。
我在这张桌子上SELECTs with UPDLOCK
观察到神秘的僵局。我看到的关于SELECTs的唯一特点是有一个内部SELECT without UPDLOCK
,但这无关紧要。该表已启用行锁定。这些SELECTS由单独的作业调度程序并行运行。这种SELECT的含义是它检索具有一个或多个指定状态的第一个(最早的)订单(上述“处理,取消,完成”)。具有最小ID的订单(在下面的查询中手动选择最小ID为6850000)被视为“第一”订单。这是出于性能原因而完成的。这是一个实际的SELECT:
select * from TORDERSUMMARY with (updlock, rowlock)
where ID in
(select min(ID) from TORDERSUMMARY
where ID > 6850000 and (ORDERSTATUS in ( 'INITIATED' ))
and (ORDERDISPATCHSTATUS in ( 0 , 2 , 4 )) and (ORDERGROUPID is null))
在表中的主键ID上定义了聚簇索引。如SQL Server Management Studio 2008所示,此类查询的估计和实际执行计划是CLUSTERED INDEX SEEK。表上有许多非聚集索引,我希望NC索引操作与聚簇索引操作死锁(我已经详细阅读了网上的一些此类情况),但由于只有聚簇索引以最好的方式使用(索引搜索),原因似乎并不存在。
内部SELECT没有UPDLOCK,ROWLOCK提示,因此没有选择带锁定的多个记录。我无法想象任何两个这样的选择会陷入僵局的情况。当然,UPDLOCK提示是因为代码随后会尝试更新订单的状态(将其标记为已处理等)。
以下是SQL Server Management Studio 2008中的一个死锁XDL文件 - http://pastebin.com/ugCUbn80。服务器本身是9.0.4035。 SQL查询很长,所以由于某种原因它们在XDL文件中被截断,但SELECTs肯定属于上述类型,因为我已经使用这样的SELECT对服务器进行了手动压力测试,并且死锁似乎随机发生在同一个方式。
答案 0 :(得分:0)
规则#1:不要在人工密钥上构建聚簇索引;在您的自然键上构建聚簇索引,并为您的人工键构建一个非聚集索引。