有多个表的事务死锁

时间:2014-03-19 20:50:00

标签: c# sql sql-server transactions sql-server-2008-r2

我的情景很常见: 我有一个存储过程需要更新多个表。 如果其中一个更新失败 - 应回滚所有更新。 海峡前线的答案是在一次交易中包括所有更新,然后回滚。但是,在像我们这样的系统中,这会导致并发问题。 当我们将更新分解为多个短事务时 - 我们在每秒之前获得大约30个并发执行的吞吐量,并且死锁问题开始出现。 如果我们把它放到一个跨越所有这些事务的事务中 - 我们会在死锁出现之前每秒并发~2次。

在我们的例子中,我们在每个短事务之后放置一个try-catch块,并手动删除/更新以前的更改。所以基本上我们以非常昂贵的方式模仿交易行为...... 它工作得很好,因为它写得很好而且没有得到很多“回滚”...... 这种方法根本无法解决的一件事是来自Web服务器/客户端的命令超时。

我已经在许多表格和博客中广泛阅读并通过MSDN进行了扫描,但找不到一个好的解决方案。许多人提出了这个问题,但我还没有看到一个好的解决方案。

问题是:是否有任何解决此问题的方法,可以更新到多个表的稳定回滚,而无需在长事务的整个持续时间内对所有行建立排他性锁定。

假设这不是优化问题。这些表几乎可能处于最大优化状态,并且只要死锁没有达到它就可以提供非常高的吞吐量。没有表锁/页锁等更新所有行锁 - 但是当你有这么多并发会话时,其中一些需要更新同一行......

它可以通过SQL,客户端C#,服务器端C#(扩展SQL服务器?)。 在我找不到的任何书籍/博客中是否有这样的解决方案?

我们正在使用SQL Server 2008 R2,并且.NET客户端/ Web服务器连接到它。 代码示例:

创建程序sptest 开始交易 更新table1 更新table2 提交交易

在这种情况下,如果sptest运行两次,则第二个实例在实例1提交之前无法更新表1。 与此相比

创建sptest2 更新table1 更新table2

Sptest2具有更高的吞吐量 - 但它有可能破坏数据。 这就是我们要解决的问题。甚至有理论上的解决方案吗?

谢谢, JS

2 个答案:

答案 0 :(得分:1)

我会说你应该深入挖掘,找出发生死锁的原因。可能您应该更改更新顺序以避免它们。也许某些指数是"有罪"。

如果其他事务可以更改数据,则无法进行更改。所以你需要对它们进行更新锁定。但您可以使用快照隔离级别在更新提交之前允许一致的读取。

答案 1 :(得分:0)

对于所有内部连接表,大多数是静态的或者很可能不会通过使用脏数据影响查询,那么您可以应用:

INNER JOIN LookupTable (with NOLOCK) lut on lut.ID=SomeOtherTableID

这将告诉查询我不关心对SomeOtherTable进行的更新

在大多数情况下,这可以减少您的问题。对于更困难的死锁,我实现了一个死锁图,当发生死锁时,该死锁图生成并通过电子邮件发送包含死锁的所有详细信息。