单个SQL Server表上的死锁

时间:2010-06-19 14:50:54

标签: c# sql-server-2008 tsql visual-studio-2008 deadlock

我正在使用SQL Server 2008 Enterprise。并使用ADO.Net + C#+。Net 3.5 + ASP.Net作为客户端访问数据库。当我访问SQL Server 2008表时,我总是从我的C#+ ADO.Net代码调用存储过程。

我在表FooTable上有3个操作。并且多个连接将在序列中同时执行它们,即执行删除,执行插入然后执行选择。 每个声明(删除/插入/选择)在单个商店过程中是单独的单个事务。

我的问题是删除语句是否可能发生死锁? 我的猜测是,如果多个连接在相同的Param1值上运行,是否可能发生死锁?

BTW:对于下面的语句,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

以下是活动监控表的外观,

ProcessID System Process Login Database Status Opened transaction Command Application Wait Time Wait Type CPU 
52 No   Foo suspended 0 DELETE .Net SqlClient Data Provider 4882 LCK_M_U 0 
53 No George Foo suspended 2 DELETE .Net SqlClient Data Provider 12332 LCK_M_U 0 
54 No George Foo suspended 2 DELETE .Net SqlClient Data Provider 6505 LCK_M_U 0 
(a lot of rows like the row for process ID 54)  

2 个答案:

答案 0 :(得分:2)

我会将Param1的索引添加到FooTable;没有它,DELETE正在进行全表扫描,这会产生死锁问题。

修改

根据您的活动详细信息,它看起来不像您有死锁,您有阻止,许多删除正在排队,同时发生一次删除。同样,对Param1进行索引可以缓解这种情况,如果没有它,每次删除都会进行全表扫描以查找要删除的记录,而当发生这种情况时,其他删除必须等待。如果你在Param1上有一个索引,它会更快地处理,你就不会看到你现在的阻塞。

如果你有死锁,系统会杀死其中一个涉及的进程,否则什么都不会处理;如果表格很大,那么事情就会处理,但事情会很慢。

答案 1 :(得分:1)

我认为你不会陷入僵局(这不是我的专业领域),但明确的交易可能是更好的选择。使用此代码时会想到的场景如下

对该过程的两个并发调用以Param1值5执行,同时删除然后同时插入,因此现在您有两个Param1值为5的记录。根据您的数据一致性要求,这可能是也可能不是你。

您可以选择实际执行更新,如果没有行受影响(请检查@@ rowcount),然后在事务中执行Insert all。或者更好的是,请查看Merge以在单个语句中执行插入/更新操作。