在SQL Server中更新单个表的行时防止死锁

时间:2015-07-06 12:57:11

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

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

另外,我创建了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的建议。

1 个答案:

答案 0 :(得分:0)

我宁愿避免像你设计的那样构造。

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

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

我认为你有两种选择。

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