SQL Server死锁问题

时间:2010-06-01 06:39:32

标签: sql-server sql-server-2008 deadlock

我正在使用SQL Server 2008 Enterprise。我想知道死锁问题是否只是由交叉依赖引起的(例如,任务A锁定了L1,但在L2上等待锁定,同时,任务B锁定了L2,但等待锁定在L1上)?是否有其他原因和情况会导致死锁?

是否还有其他导致死锁的方法 - 例如超时(S / I / D / U语句很长时间没有返回,并且会返回死锁错误)或者无法长时间获取锁定但不是由交叉依赖性引起的(例如任务C需要获取)锁定表T,但另一个任务D获取表T上的锁而不释放锁,这导致任务C无法长时间锁定表T?)

编辑1:如果多个线程同时执行此存储过程会导致死锁吗?

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  
提前谢谢, 乔治

3 个答案:

答案 0 :(得分:2)

死锁需要一个循环,其中资源被等待其他进程持有的锁以释放锁的进程锁定。任何数量的进程都可以参与死锁,检测死锁的常规方法是获取锁的依赖关系图并搜索该图中的循环。

你需要让这个循环存在死锁。其他任何事情只是一个等待锁定被释放的过程。 sp_who2是一种快速查看其他进程被阻止的进程的方法。

如果要对死锁进行故障排除,最好的方法是运行跟踪,获取“死锁图”事件。这将允许您通过告诉您哪些查询持有锁来查看正在发生的事情。

答案 1 :(得分:2)

还有转换死锁:进程A和B都在资源C上有共享锁。两者都希望在C上获得独占锁。

即使两个进程只在一个资源上竞争,它们仍然可以陷入僵局。以下脚本重现了这种情况。在一个选项卡中,运行:

CREATE TABLE dbo.Test ( i INT ) ;
GO
INSERT  INTO dbo.Test
        ( i )
VALUES  ( 1 ) ;
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
BEGIN TRAN
SELECT  i
FROM    dbo.Test ;

--UPDATE dbo.Test SET i=2 ;

此脚本完成后,我们有一个持有共享锁的未完成事务。在另一个选项卡中,让我们让另一个连接在同一资源上具有共享锁:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
BEGIN TRAN
SELECT  i
FROM    dbo.Test ;

--UPDATE dbo.Test SET i=2 ;

此脚本完成并呈现结果集,就像第一个脚本一样。现在让我们在两个选项卡中突出显示并执行注释的更新命令。要执行更新,每个连接都需要一个独占锁。两个连接都不能获得该独占锁,因为另一个连接是持有共享锁。虽然两个连接只在一个资源上竞争,但它们已经接受了转换死锁:

Msg 1205,Level 13,State 56,Line 1 事务(进程ID 59)在锁资源上与另一个进程发生死锁,并被选为死锁牺牲品。重新运行该交易。

另请注意,死锁可能包含两个以上的连接。

答案 2 :(得分:0)

长时间不释放锁定并不是一个僵局。

僵局是一种永远无法前进的局面。它是由等待其他人完成的2个(或更多)进程引起的,但所有涉及的进程都持有阻止其他进程继续的锁。

解决死锁的唯一方法就是杀死进程以释放锁,因为无论你等待多久都无关紧要,它无法自行完成。