代码之家  ›  专栏  ›  技术社区  ›  Saurabh Kumar

多个存储过程如何同时更新同一行?

  •  0
  • Saurabh Kumar  · 技术社区  · 15 年前

    我正在使用ssis 2008在控制流中并行执行多个存储过程。 每个SP应该最终更新一个表中的1行。

    需要注意的是,每个SP都有一个定义的职责,只更新特定的列。

    可以保证不同的SP不会更新彼此的列。因此,要更新的列在不同的SP之间进行划分,但根据设计,每个SP最终应该在同一行上工作。

    目前我的一些SPS由于死锁而出错。我猜这可能是因为其他SP锁定了那一行?

    我怎么解决这个问题?

    5 回复  |  直到 15 年前
        1
  •  1
  •   sfuqua    15 年前

    你必须承认,这似乎是一件非常不寻常的事情。我想知道是否最好先更新单独的表,然后在末尾有一个将单个表连接到最后一个表的update语句?(即 update a set a.[1] = ... from a inner join b inner join c 等等)。

    但是,如果您希望继续沿着此路径运行,那么只需在每个存储过程中设置未提交的读取。这是最好的选择。

        2
  •  1
  •   bobs    15 年前

    死锁可能不仅仅是由另一个SP锁定行引起的。在这种情况下,第一个过程只需等待锁定SP释放锁定。这并不是说你的多重程序没有引起问题。不过还有很多。

    为了避免这个问题,您可能需要做一些修改,但是首先您应该了解更多关于死锁情况的信息。我怀疑您锁定了正在更新的行以外的对象。

    有很多方法可以收集关于死锁的更多信息。这里有一个 link 在这里您可以了解死锁的详细信息。

        3
  •  0
  •   TomTom    15 年前

    简单:做诉讼,你不留任何地方的锁。这与由连接确定的事务隔离一起工作。由于属性事务是易失的,因此不会有锁,因此不会出现死锁。

    更新不是问题所在。它从阅读开始。转到“未斜接读取”以确保在读取时不保留锁,和/或使用select语句中的nolock选项单独强制它们在读取数据时不保留锁(更可取)。 然后,如果确保SP在插入之后(内部或外部)立即提交,则不可能出现死锁-写锁将导致下一个SP等待提交第一个事务。

    尤其是当只访问一个表/一行时,死锁不可能只使用update语句IIRC。是读锁把延迟锁(尽管延迟很小)变成了死锁。

    http://www.eggheadcafe.com/software/aspnet/30976898/how-does-update-lock-prevent-deadlocks.aspx 有一些死锁的好例子。因此,如果除了更新之外的所有内容都没有锁,那么最后就不可能出现死锁。

        4
  •  -1
  •   KMW    15 年前

    行级锁定是尽可能低的,所以我认为您必须将更新的表分解成几个表,您可以独立地更新它们。

        5
  •  -1
  •   Patrick Marchand    15 年前

    不,两个会话不能同时更新同一行。行级锁定是尽可能低的,因此当一个会话更新一行时,其他希望更新该记录的会话将等待。

    至于死锁,SQL Server的问题在于,默认情况下,如果select语句请求当前正在更新的记录,它将阻塞。如果不介意读取未提交的数据,可以使用with(nolock)。

    所以,如果你有这样的事件顺序: 休会

    begin transaction
    
    update t1
    set c1 = 'x'
    where c2 = 5
    
    SessionB
    
    begin transaction
    
    update t2 
    set c1 = 'y'
    where c2 = 7
    
    SessionA
    
    select * from t1 where c2 = 5
    <waits on SessionB>
    
    SessionB
    select * from t2 where c2 = 7
    <waits on SessionA>...oops. Deadlock.
    

    诀窍是只在必要的最短时间内锁定某个对象(不要为了释放锁而分解一系列语句-确保构成逻辑事务的步骤保持为事务):

    begin transaction
    
    update t1
    set c1 = 'x'
    where c2 = 5
    
    commit
    

    或(警告清空器)使用nolock指令:

    SessionA
    
    select c1 from t1 where c2 = 5 with (nolock)
    <gets the new value of 'x'>
    
    SessionB
    select * from t2 where c2 = 7 with (nolock)
    <gets the new value of 'y'>