简体   繁体   English

单个SQL Server表上的死锁

[英]deadlock on a single SQL Server table

I am using SQL Server 2008 Enterprise. 我正在使用SQL Server 2008 Enterprise。 And using ADO.Net + C# + .Net 3.5 + ASP.Net as client to access database. 并使用ADO.Net + C#+。Net 3.5 + ASP.Net作为客户端访问数据库。 When I access SQL Server 2008 tables, I always invoke stored procedure from my C# + ADO.Net code. 当我访问SQL Server 2008表时,我总是从我的C#+ ADO.Net代码调用存储过程。

I have 3 operations on table FooTable. 我在表FooTable上有3个操作。 And Multiple connections will execute them at the same time in sequences, ie executes delete, the execute insert and then execute select. 并且多个连接将在序列中同时执行它们,即执行delete,execute insert然后执行select。 Each statement (delete/insert/select) is of a separate individual transaction in the single store procedure. 每个语句(删除/插入/选择)都是单存储过程中的单独的单个事务。

My question is whether it is possible that deadlock will occur on delete statement? 我的问题是,删除语句是否可能发生死锁? My guess is whether it is possible that deadlock occurs if multiple connections are operating on the same Param1 value? 我的猜测是,如果多个连接在同一个Param1值上运行,是否可能发生死锁?

BTW: For the statements below, Param1 is a column of table FooTable, Param1 is a foreign key of another table (refers to another primary key clustered index column of the other table). BTW:对于下面的语句,Param1是表FooTable的列,Param1是另一个表的外键(指另一个表的另一个主键聚簇索引列)。 There is no index on Param1 itself for table FooTable. 对于表FooTable,Param1本身没有索引。 FooTable has another column which is used as clustered primary key, but not Param1 column. 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

Here is what the activity monitor table looks like, 以下是活动监视器表的外观,

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)  

I would add an index on Param1 to FooTable; 我会在Param1上添加一个索引到FooTable; without it, the DELETE is doing full table scan, and that'll create problems with deadlocks. 没有它,DELETE正在进行全表扫描,这会产生死锁问题。

EDIT 编辑

Based on your activity details, it doesn't look like you have deadlocks, you have blocking, many deletes are queueing up while one delete takes place. 根据您的活动详细信息,它看起来不像您有死锁,您有阻塞,许多删除正在排队,同时发生一次删除。 Again, indexing on Param1 would alleviate this, without it, each delete is going to do a full table scan to find the records to delete, while that is happening, the other delete's have to wait. 同样,对Param1进行索引可以缓解这种情况,如果没有它,每次删除都会进行全表扫描以查找要删除的记录,而当发生这种情况时,其他删除必须等待。 If you have an index on Param1, it'll process much quicker and you won't see the blocking you are now. 如果你在Param1上有一个索引,那么它的处理速度会快得多,你就不会看到你现在的阻塞。

If you have deadlocks, the system will kill one of the involved processes, otherwise nothing would ever process; 如果你有死锁,系统将杀死一个涉及的进程,否则什么都不会处理; with blocking, things will process, but very slowly if the table is large. 如果表格很大,那么事情就会处理,但事情会很慢。

I do not think you would get a deadlock (this is not my field of expertise), but an explicit transaction would probably be a better choice here. 我不认为你会陷入僵局(这不是我的专业领域),但明确的交易可能是更好的选择。 A scenario that comes to mind with this code is the following 此代码会想到一个场景如下

Two concurrent calls to the procedure execute with Param1 value of 5, both delete and then both insert, so now you have two records with Param1 value of 5. Depending on your data consistency requirements this might or might not be a concern to you. 对该过程的两个并发调用以Param1值5执行,同时删除然后同时插入,因此现在您有两个Param1值为5的记录。根据您的数据一致性要求,这可能会或可能不会引起您的关注。

An alternative for you might be to actually perform an Update and if no rows are affected (check @@rowcount) then do an Insert all in a transaction of course. 您可以选择实际执行更新,如果没有行受影响(请检查@@ rowcount),然后在事务中执行Insert all。 Or better yet, take a look at Merge to perform Insert/Update operation in a single statement. 或者更好的是,请查看Merge以在单个语句中执行插入/更新操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM