这样的存储过程会导致死锁吗?

Posted

技术标签:

【中文标题】这样的存储过程会导致死锁吗?【英文标题】:Will such a stored procedure cause deadlock? 【发布时间】:2010-06-04 15:25:39 【问题描述】:

我使用的是 SQL Server 2008 Enterprise。我想知道如果同时由多个线程执行,这个存储过程是否会导致死锁?另一个问题是——我们是在存储过程中定义开始和结束事务的最佳实践,还是从客户端代码(例如 ADO.Net 代码)定义开始和结束事务?

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  

提前致谢, 乔治

【问题讨论】:

在 SQL 2008 中 MERGE 能满足您的需求吗?也绝对应该避免@@Identity。使用 SCOPE_IDENTIY 是的,我目前正在分析遗留代码的一些问题,我需要分析死锁是否是由这个存储过程引起的。关于我原来的问题有什么想法或想法吗? @@IDENTITY 提供最新的身份值,如果有触发器,您会从中获取身份,而不是从本地范围内的 INSERT 获取身份。 SCOPE_IDENTITY() 给出本地范围的标识值。使用分析器和死锁图来确定死锁涉及哪些过程。 @George2 - DELETE FooTable WHERE Param1 = @Param1 通常会删除多少条记录? Param1 上是否有索引?如果它需要获得相当多的锁,那么死锁肯定会以类似于此线程***.com/questions/2945135/… 的方式发生。正如 KM 建议的那样,设置跟踪以获取死锁图会更有效率。 @George2 我的推理方式是,受影响的记录数越多,锁的数量就越多,它们的粒度就越小。 【参考方案1】:

回答您问题的唯一可靠方法是run your own stress tests

【讨论】:

对不起,亚历克斯,问题不是很清楚。请在这里讨论,我对此有更清晰的描述。 ***.com/questions/2981121/…【参考方案2】:

您提供的代码可能导致死锁。即使存储过程纯粹由以下语句组成,也可能发生死锁。

   DELETE FooTable WHERE  Param1 = @Param1

取决于可用的确切表定义和索引(您已将其排除在问题之外)。

【讨论】:

为什么包含这个delete语句会导致死锁?还有更多细节吗?我想了解为什么 Param1 上是否有索引会导致死锁? 好吧,我的想法是假设存储过程的调用 1 最终会在页面 x、y、z 上获得页面锁定,但需要页面 a。存储过程的调用 2 最终会在页面 a、b、c 上获得页面锁定,但需要页面 x 然后会发生死锁。 @George2 我们不知道有多少页面会受到影响,因为您没有告诉我们! 我绝对不是死锁大师!查看 Remus Rusanu 的帖子***.com/search?q=user%3A105929+deadlock 单条删除语句还是单条删除记录?如果是后者,那么我也无法构建会发生这种情况的场景。如果是前者,那么我给出的前面的例子就可以做到(可能依赖于并行执行计划只是为了确保锁不是以线性顺序发出的)。

以上是关于这样的存储过程会导致死锁吗?的主要内容,如果未能解决你的问题,请参考以下文章

由于 2 个会话同时访问相同的存储过程,导致事务(进程 ID)死锁

mysql 存储过程出现死锁

存储过程会导致内存泄漏吗?

通过 callproc 调用存储过程会导致缓存膨胀吗?

一个存储过程中更新多个表可以用一个COMMIT吗 ?

更新存储过程中的死锁