我正在使用SQL Server 2008 Enterprise。我想知道为什么即使这个存储过程的单个delete语句如果同时由多个线程执行也会导致死锁?
对于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
提前谢谢,
乔治
答案 0 :(得分:2)
我没有并发经验但是你的程序中有两件事我会改变(并且可能会修复你的死锁):
Interesting link关于@@ Identity vs SCOPE_IDENTITY()vs IDENT_CURRENT()
答案 1 :(得分:1)
通常的答案:这取决于! : - )
主要取决于您的系统流量以及您正在使用的事务隔离级别。
隔离级别控制您获取数据的方式以及锁定的数量。 如果您从未听说过事务隔离级别,那么您可能正在使用默认值 - READ COMMITTED,这应该是一个不错的选择。
但是,如果出于任何原因使用SERIALIZABLE
之类的内容,您可能会遇到死锁 - 但会延迟。在一个事务完成之前,表可能会被锁定一段时间。如果所有操作按此顺序工作(首先删除,然后插入,然后选择),我看不出你应该如何遇到任何死锁,真的。
在www.sql-server-performance.com上阅读SQL事务隔离级别。
答案 2 :(得分:0)
如果一个大表BarTable有一个引用FooTable的外键约束,那么删除FooTable中的一行就需要检查所有BarTables行以获取对该行的引用。
这不仅非常慢,而且变得更糟:在执行此检查时,FooTable中两个并发删除的两个单行可能会在BarTable的主键上出现死锁(!)
如果在BarTable上为引用FooTable的列创建索引,则删除可以使用该索引来显着加快速度。
所以:
确保您的外键约束由索引备份。