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

时间:2010-08-07 02:49:30

标签: sql sql-server-2008 ssis asynchronous deadlock

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

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

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

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

我该如何解决这个问题?

5 个答案:

答案 0 :(得分:1)

死锁可能不仅仅是让另一个SP锁定该行。在这种情况下,第一个程序将等到锁定SP释放锁定。这并不是说您的多个程序不会导致问题。不过还有更多。

您可能需要做一些返工以避免问题,但首先您应该了解有关死锁情况的更多信息。我怀疑你对除了正在更新的行以外的对象有锁定。

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

答案 1 :(得分:1)

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

但是,如果您想继续沿着这条路走下去,那么只需在每个存储过程中设置READ UNCOMMITTED即可。这是最好的选择。

答案 2 :(得分:0)

简单:制作suere你不要把锁留在任何地方。这适用于由连接确定的事务隔离。使用正确的事务isaolation,将没有锁,因此没有死锁。

更新不是问题。它从READS开始。转到READ UNCOMMITED以确保在读取时不保留锁定,和/或使用SELECT语句中的NOLOCK选项单独强制它们保留NO LOCKS以便读取数据(更可取)。 如果然后确保SP在插入(内部或外部)之后几乎立即提交,则应该没有死锁 - 写锁定将导致下一个SP等待第一个事务提交。

特别是当仅限于一个表/一行时,仅使用更新语句IIRC就无法实现死锁。它是读锁,它将延迟锁定(虽然是小延迟)变成死锁。

http://www.eggheadcafe.com/software/aspnet/30976898/how-does-update-lock-prevent-deadlocks.aspx有一个很好的死锁示例。因此,如果所有内容但是更新没有锁定,那么最终就无法实现死锁。

答案 3 :(得分:-1)

行级别锁定尽可能低,所以我认为您必须将更新的表拆分为几个可以彼此独立更新的表。

答案 4 :(得分:-1)

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

至于死锁,SQL Server的问题在于,如果要求当前正在更新的记录,SELECT语句将默认阻止。如果您不介意阅读未提交的数据,可以使用WITH(NOLOCK)。

所以,如果你有这个事件顺序: SessionA

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.

诀窍是只在必要的时间内锁定一些东西(不要为了释放锁而分解一系列语句 - 确保构成逻辑事务的步骤保留为事务): / p>

begin transaction

update t1
set c1 = 'x'
where c2 = 5

commit

Or(caveat emptor)使用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'>