简体   繁体   English

与多个表进行交易时出现死锁

[英]Deadlock on transaction with multiple tables

My scenario is common: I have a stored procedure that need to update multiple tables. 我的情况很常见:我有一个存储过程,需要更新多个表。 if one of updates failed - all the updates should be rolled back. 如果更新之一失败-应该回滚所有更新。 the strait forward answer is to include all the updates in one transaction and just roll that back. 海峡前进的答案是将所有更新包含在一个事务中,然后回滚。 however, in system like ours , this will cause concurrency issues. 但是,在像我们这样的系统中,这将导致并发问题。 when we break the updates into multiple short transactions - we get throughput of ~30 concurrent executions per second before and deadlocking issues start to emerge. 当我们将更新分为多个短事务时-之前每秒获得约30个并发执行的吞吐量,并且开始出现死锁问题。 if we put it to one transaction which span all of them - we get concurrent ~2 per second before deadlock shows up. 如果我们将它放到一个涵盖所有事务的事务中,则在出现死锁之前,每秒并发速度约为2。

in our case, we place a try-catch block after every short transaction, and manually DELETE/Update back the changes from the previous ones. 在我们的例子中,我们在每个短事务之后放置一个try-catch块,并手动删除/更新先前的更改。 so essentially we mimic the transaction behavior in a very expensive way... It is working alright since its well written and dont get many "rollbacks"... one thing this approach cannot resolve at all is a case of command timeout from the web server / client. 因此从本质上讲,我们以一种非常昂贵的方式来模仿事务行为...它工作正常,因为其编写得很好,并且没有得到很多“回滚” ...这种方法根本无法解决的一件事是来自网络的命令超时情况服务器/客户端。

I have read extensively in many forms and blogs and scanned through the MSDN and cannot find a good solution. 我已经阅读了许多形式和博客的大量文章,并通过MSDN进行了扫描,但找不到合适的解决方案。 many have presented the problem but I am yet to see a good solution. 许多人提出了这个问题,但是我还没有看到一个好的解决方案。

The question is this: is there ANY solution to this issue that will allow a stable rollback of update to multiple tables, without require to establish exclusivity lock on all of the rows for the entire duration of the long transaction. 问题是:此问题是否有解决方案,可以稳定地回滚更新多个表,而无需在长事务的整个过程中在所有行上建立排他性锁定。

Assume that it is not an optimization issue. 假定这不是优化问题。 The tables are almost at the max optimization probably, and can give a very high throughput as long as deadlock don't hit it. 这些表几乎处于最大优化状态,并且只要没有死锁就可以提供很高的吞吐量。 there are no table locks/page locks etc. all row locks on updates - but when you have so many concurrent sessions some of them need to update the same row... 没有表锁/页面锁等。所有行锁都更新-但是,当您有这么多并发会话时,其中一些需要更新同一行...

it can be via SQL, client side C#, server side C# (extend the SQL server?). 它可以通过SQL,客户端C#,服务器端C#(扩展SQL Server?)来实现。 Is there such solution in any book/blog that i have not found? 在我没有找到的任何书籍/博客中都有这样的解决方案吗?

we are using SQL server 2008 R2, with .NET client/web server connecting to it. 我们正在使用SQL Server 2008 R2,并将.NET客户端/ Web服务器连接到它。 Code example: 代码示例:

Create procedure sptest Begin transaction Update table1 Update table2 Commit transaction 创建过程sptest开始事务更新表1更新表2提交事务

In this case, if sptest is run twice, the second instance cannot update table 1 until instance 1 has committed. 在这种情况下,如果sptest运行两次,则第二个实例将无法更新表1,直到实例1提交为止。 Compared to this 与此相比

Create sptest2 Update table1 Update table2 创建sptest2更新表1更新表2

Sptest2 has a much higher throughput - but it has chance to corrupt the data. Sptest2具有更高的吞吐量-但它有机会破坏数据。 This is what we are trying to solve. 这就是我们要解决的问题。 Is there even a theoretical solution to this? 有没有理论上的解决方案?

Thanks, JS 谢谢,JS

I would say that you should dig deeper to find out the reason why deadlock occurs. 我想说,您应该更深入地了解死锁发生的原因。 Possibly you should change the order of updates to avoid them. 可能您应该更改更新顺序以避免它们。 Maybe some index is "guilty". 也许有些索引是“有罪的”。

You cannot roolback changes if other transactions can change data. 如果其他事务可以更改数据,则无法回滚更改。 So you need to have update lock on them. 因此,您需要对它们进行更新锁定。 But you can use snapshot isolation level to allow consistent reads before update commits. 但是您可以使用快照隔离级别来允许在更新提交之前进行一致的读取。

For all inner joined tables that are mostly static or with a high degree of probability not effect the query by using dirty data then you can apply: 对于所有大多数是静态的或具有较高概率的内部联接表,通过使用脏数据不会影响查询,则可以应用:

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

This will tell the query that I do not care about updates made to SomeOtherTable 这将告诉查询我不在乎对SomeOtherTable所做的更新

This can reduce your issue in most cases. 在大多数情况下,这可以减少您的问题。 For more difficult deadlocks I have implemented a deadlock graph that is generated and emailed when a deadlock occurs contains all the detailed info for the deadlock. 对于更困难的死锁,我实现了一个死锁图,该死锁图在死锁发生时生成并通过电子邮件发送,其中包含该死锁的所有详细信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM