【问题标题】:Occasional Deadlock偶尔的死锁
【发布时间】:2008-12-01 01:31:34
【问题描述】:

我遇到了一个偶尔会死锁的网络应用程序

涉及 3 个查询。 2 正在尝试更新表

UPDATE AttendanceRoll
SET ErrorFlag = 0
WHERE ContractID = @ContractID
AND DATEPART(month,AttendanceDate) = DATEPART(month,@Month_Beginning)
AND DATEPART(year,AttendanceDate) = DATEPART(year,@Month_Beginning)

一个人正试图插入到表中

INSERT INTO AttendanceRoll 
    (AttendanceDate, ContractID, PersonID, 
    StartTime, 
    EndTime, 
    Hours, AbsenceReason,
    UpdateCount, SplitShiftID, ModifiedBy, ModifiedDate)
SELECT   
    @P33,  @P34,  @P35,
    CONVERT(datetime,REPLACE( @P36, '.', ':')),
    CONVERT(datetime,REPLACE( @P37, '.', ':')),
    @P38,  @P39,  
    @P40, 1,  @P41, GETDATE()

死锁图显示了页面锁和交换事件的一种循环排列,并且 2 个更新查询具有相同的服务器进程 ID。

如果有人对我应该如何解决这个问题有任何想法,将不胜感激。

如果有人需要,我可以发布死锁图。

谢谢 卡尔R

【问题讨论】:

  • 请贴出图表,表格定义(包括任何索引)

标签: sql-server sql-server-2005 deadlock


【解决方案1】:

更新查询是否需要很长时间才能执行(例如,超过一秒)?如果是这样,请尝试优化查询(即通过在 contractid 列上放置索引等)

修复死锁时我总是喜欢做的第一件事就是调整所涉及的查询。如果您能获得良好的性能提升,那么您将受益于更快的查询,以及大大降低发生死锁的机会。

【讨论】:

    【解决方案2】:

    --经过jorgeburgos的建议,然后……

    如果这是一个僵局,那么,假设只有 2 名参赛者,一名应该是受害者,一名将完成。

    您可以在数据层中内置死锁检测,并让它重试因死锁而失败的操作。

    使用不同的表提示锁定机制来最小化争用资源的范围。我不知道哪个适用于您使用的 sql 版本,但这里来自 MSDN。 http://msdn.microsoft.com/en-us/library/ms187373.aspx

    【讨论】:

      【解决方案3】:

      我猜你的更新正在执行表扫描,并最终将行锁升级为页锁到表锁,这会阻止插入完成

      我认为有一个设置可以告诉它不要升级到行锁定之外,你可以先尝试一下

      如果做不到这一点,您可能必须分离并索引月份数据以提高更新效率

      【讨论】:

        【解决方案4】:

        如果不查看死锁图和所涉及的工作负载,并且根据您所说的存在交换,您可能会遇到涉及并行的死锁。 http://msdn.microsoft.com/en-us/library/aa937571(SQL.80).aspx。你的死锁图看起来像上一篇文章中的那个吗?

        您可以为查询禁用 parralesim 吗?有一个提示 OPTION (MAXDOP 1) 将在特定查询中禁用它。打开它,看看它是否有帮助。 http://msdn.microsoft.com/en-us/library/ms181714.aspx

        优化索引还可以通过首先消除对并行的需求来缓解死锁。

        【讨论】:

          【解决方案5】:

          我通常将所有对 SQL Server 的调用封装在类似的东西中(确切地说,这不会编译,但你会明白的):

          for (;;) {
              try {
                  using (var t = BeginTransaction()) {
                      DoTheCall();
                      t.Commit();
                      return;
                  }
              }
              catch (SqlException ex) {
                  if (ex.Number != 1205 && ex.Number != 601 && ex.Number != 605)
                      throw;
              }
          }
          

          【讨论】:

          • 在这种情况下设置某种事务重启计数器不是很明智吗?
          猜你喜欢
          • 2021-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-30
          • 1970-01-01
          • 1970-01-01
          • 2014-09-29
          相关资源
          最近更新 更多