2010-06-05 155 views
1

我正在使用SQL Server 2008 Enterprise。我想知道为什么即使这个存储过程的单个删除语句会导致死锁,如果多个线程同时执行?为什么单个SQL删除语句会导致死锁?

对于delete语句,Param1是表FooTable的列,Param1是另一个表的外键(引用另一个表的另一个主键聚簇索引列)。对于表FooTable,Param1本身没有索引。 FooTable有另一列用作聚集主键,但不是Param1列。

create PROCEDURE [dbo].[FooProc]  
( 
@Param1 int 
,@Param2 int 
,@Param3 int 
)  
AS  

DELETE FooTable WHERE Param1 = @Param1  

INSERT INTO FooTable  
( 
Param1 
,Param2 
,Param3 
)  
VALUES  
( 
@Param1 
,@Param2 
,@Param3 
)  

DECLARE @ID bigint  
SET @ID = ISNULL(@@Identity,-1)  
IF @ID > 0  
BEGIN  
     SELECT IdentityStr FROM FooTable WHERE ID = @ID 
END 

由于事先 乔治

+2

捕获死锁图并将其添加到您的帖子。直到那时,我们都在猜测。有关如何捕获死锁图的信息,请参见http://msdn.microsoft.com/en-us/library/ms190465.aspx。 – 2010-06-05 20:53:28

+0

嗨Remus,如何触发死锁?任何工具或示例代码来进行压力测试? – George2 2010-06-06 07:18:39

+1

通过查看您的过程,我注意到您删除基于Param1的所有行,然后只插入1行。你不能使用UPDATE语句吗? – ZippyV 2010-06-07 07:45:30

回答

1

通常的答案:这取决于! :-)

主要表现在您的系统上有多少流量,以及您使用的是什么事务隔离级别。

隔离级别控制你如何获取数据以及进行多少锁定。 如果您从未听说过事务隔离级别,那么您可能使用了默认设置 - READ COMMITTED,这应该不是太糟糕的选择。

但是,如果您出于任何原因使用诸如SERIALIZABLE之类的内容,您可能会遇到没有死锁 - 但延迟。该表可能会锁定一段时间,直到完成一笔交易。如果所有的操作按照这个顺序工作(首先删除,然后插入,然后选择),我真的没有看到你会遇到任何死锁。

请阅读www.sql-server-performance.com上的SQL事务隔离级别。

+1

我在@ George2的上一个死锁线程上声称,如果两个并发删除操作都以并行执行计划和按“正确”顺序分配页锁来导致此问题,那么死锁可能会在两个并发删除之间出现。然而,我只是试图让这个僵局发生在测试中,而不能。如果我在那里误导你@乔治2,我没有时间去追求它了! – 2010-06-05 19:18:17

+0

嗨马克,可用于重现死锁情况的任何工具或示例代码? – George2 2010-06-06 07:34:30

+0

嗨马丁,任何想法为什么在我的场景有僵局?任何可用于重现死锁场景的工具或示例代码? – George2 2010-06-06 07:38:04

2

我没有并发的经验,但有两件事情在你的过程,我会改变(也许修复你死锁):

  • 在交易中包装整个过程。这是为了防止像FooProc 1这样的场景被称为 ,并且即将执行SELECT语句,而FooProc 2刚刚执行了具有相同@Param1的DELETE语句。
  • 请勿使用@@ Identity,而应使用SCOPE_IDENTITY。

Interesting link约@@身份VS SCOPE_IDENTITY()与IDENT_CURRENT()

+0

感谢ZippyV,任何想法为什么在我的场景中存在僵局?任何可用于重现死锁场景的工具或示例代码? – George2 2010-06-06 07:39:00

+1

http://www.mssqltips.com/tip.asp?tip=1036 – ZippyV 2010-06-06 10:45:07

+0

如果Table FooTable很大,你认为我的场景会导致死锁吗? – George2 2010-06-06 15:28:22

0

如果大型表BarTable具有引用FooTable的外键约束,那么删除FooTable中的单个行需要检查所有BarTables行以引用该行。

这不仅是惊人速度慢,事情变得更糟糕:一边做这个检查,在FooTable两个单排的两个并行的缺失可以得到僵持BarTable的主键

如果创建一个索引(!)在引用FooTable的列的BarTable上,删除可以使用该索引来显着加快速度。

所以:

请确保您的外键约束是通过索引备份。