【问题标题】:Prevent Deadlock when updating rows of a single table in SQL Server在 SQL Server 中更新单个表的行时防止死锁
【发布时间】:2015-07-06 12:57:10
【问题描述】:

我有一个名为Banners 的表,其中包含BIDimpressions 等列...

另外,我创建了StoredProcedure,它在网页加载时执行。

存储过程

 DECLARE @slot int               
 DECLARE @final varchar(MAX)               
 DECLARE @URL varchar(MAX)             
 DECLARE @ID varchar(MAX)                
 set @slot =0               
 SET @URL='';               
 SET @ID=0                      
 SET @final='';                  

 BEGIN               
 WHILE(@slot <= 6)               
 BEGIN               
 SET @slot= @slot+1             

IF EXISTS(select BID from Banners (NOLOCK) where Slot=@slot AND SectionID =199 AND UserType in (@IsAnonymous,2) AND Enabled=1)               
 BEGIN                  
  SET @final = (select TOP 1 '<div class=''sidebar-img''><a href ='''+ URL +''' id='''+CONVERT(varchar(10),BannerID)            
  +''' target=''_blank'' onclick=''Click(this)'';><img alt='''+Alt+''' src='''+BannerImage+''' height=''250'' width=''250''></a></div>'                  
  FROM Banners (NOLOCK) where Slot=@slot AND  Enabled=1 AND UserType in (@IsAnonymous,2)                   
  AND SectionID =199
  ORDER BY CHECKSUM(NEWID()))            

 IF(@final<>'')               
 BEGIN               
  SET @URL  = @URL + @FINAL            
  SET @ID =(select replace( (select SUBSTRING(@final,charindex(' id=',@final)+5,4)),'''',''));                  
  UPDATE Banners set impressions +=1 where BID=CONVERT(INT,@ID); <-- **this causes DEADLOCK**                  
 END               
 ELSE               
  SET @URL  = @final              
 END                
 ELSE              
 BEGIN            
  CONTINUE            
 END                     
 END                     
  SET @BannerHTML = @URL         
 END                 

主要是 deadlock issue 发生在 update statement 上,我们正在更新 Banners Table

请告诉我任何阻止Deadlock 的建议。

【问题讨论】:

  • 好吧,只有当两个进程在同一资源上并行运行时,才有可能发生死锁。您是否检查了哪两个进程发生冲突?您是否已经知道根本原因,现在尝试避免它?如果是这样,你能提供碰撞的查询吗?这会很有帮助。
  • @Ionic 我已经在 SP 中总结了......
  • 是的,但你不能自己陷入僵局!锁是按会话设计的。如果您的过程在一个会话中运行,它本身就可以访问所有锁定的资源。这意味着您不能与自己的过程发生死锁。除了(未包含在您的文本中)您并行运行相同的过程(同时多次)。你呢?
  • 当两个进程以不同的顺序访问相同的资源时,就会发生死锁。进程 A 持有资源 X 并追求资源 Y。进程 B 持有资源 Y 并追求资源 X。进程 A 和 B 永远等待对方“放手”他们想要的资源。 SQL Server 声明死锁。您需要使用死锁事件执行 SQL 跟踪/配置文件,并查看什么是死锁,以及 WHO。
  • @Ionic 是的,我试过了,在更新声明中说是死锁

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


【解决方案1】:

我宁愿避免你设计的这种结构。

首先,我认为您的对象Mercola_Banners 是一个使用您的表Banners 的视图,对吗?这可能会导致死锁。

无论如何,如果你有一个像横幅这样的表格,我会避免直接更新它,它会经常更新。

在我看来你有两个选择。

  1. 如果您的应用程序允许,您可以使用OPTIMISTIC LOCKING,它将使用您的一些 tempdb 来存储您的行的版本。在这种情况下,每个事务都可能使用不同版本的行。这意味着,如果您的事务运行,它可能会使用您的行的版本一。更新横幅表后,它会创建第二个版本。如果发生下一页加载,它将使用该行的第二版并将其更新为第三版。如果第一个事务结束,则不再引用版本一,它将被删除。 但是,它可能会导致一些错误的更新,如果您几乎同时运行两个事务,它们可能会相互重叠。示例:事务 1 启动,读取版本 1。事务 2 启动,它也读取版本 1。事务 1 将该行更新为版本 2(将展示次数更新为 2)。在下一步中,事务 2 生成另一行作为版本 3(它还将展示次数从 1 更新到 2)。最后,事务 2 和事务 3 结束,最后只存在版本 3。这意味着您有 2 次展示,而不是真正的 3 次展示。这可能是您的问题。
  2. 您应该(我建议在压力较高的区域)使用插入临时表代替。暂存表可以每分钟或每 5 分钟(例如)解释一次,并用于更新impressions-column。更新行后,您可以从临时表中删除行。这样你就可以解耦更新。在更新过程中,您可能会导致排他锁,这会阻止读取banners-表。插入只会导致排他行锁定,这应该不会造成太大影响。

【讨论】:

  • 应该是横幅而不是 Mercola_Banners
  • 再次检查 SP...我已经修改
  • 啊,好吧。无论如何,这对我来说是相同的答案。我刚刚提到了这个观点,因为我认为它也指向了横幅。这意味着我是对的可能性比你更新之前更高。
猜你喜欢
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-11
相关资源
最近更新 更多