据我所知,当SPID忙于处理另一个查询时会发生SQL死锁,并且因为它现在很忙而无法再运行另一个查询。 SQL Server“随机”选择其中一个查询从请求的资源中解锁,并将其取消,抛出异常。
我有一个应用程序运行~40个实例和一个后端Windows服务,所有这些都在同一个数据库中。我希望减少死锁,这样我就可以增加可以同时运行的线程数。
答案 0 :(得分:20)
您对死锁的理解不正确。你所描述的是封锁。将这两者等同起来是一个常见的错误。
当两个单独的事务都需要不同的资源时,就会发生死锁,并且两个事务都不会释放它们拥有的那个以便另一个可以运行。它可能更容易说明:
SPID#1获取资源A的锁定 SPID#2获取资源B的锁定 SPID#1现在需要锁定资源B才能完成 SPID#2现在需要锁定资源A才能完成
SPID#1无法完成(因此发布资源A),因为SPID#2拥有它 SPID#2无法完成(因此发布资源B)因为SPID#1有它
由于SPID都不能完成,因此必须放弃(即由服务器选择作为死锁受害者)并且将失败。
避免它们的最佳方法是保持交易量小(需要的资源数量)并且快速。
答案 1 :(得分:3)
死锁是两个处理线程都被另一个处理所阻塞的地方(可能更多,但两个处理足够复杂)。因此,一个线程锁定一个表,然后请求另一个表上的锁。另一个表被第二个线程锁定,因为它正在等待第一个表上的锁定而无法进行。
其中一个必须被抛出的原因是,在死锁中,它们永远不会结束 - 两个线程都不会进展。唯一的答案是让一个人停下来让对方完成。
在您谈论的某种情况下减少死锁的解决方案可能是重新设计解决方案。如果您可以确保发生锁定较少,则可以减少死锁。
答案 2 :(得分:1)
发生死锁是因为,两个并发事务可能会重叠锁定不同的资源,这两个资源都需要另一个事务完成。
让我们想象一下: 1 - 事务A锁定row1 2 - 事务B锁定row2 3 - 事务A尝试锁定row1,并且由于先前的锁定,SQL服务器等待 4 - 事务B尝试锁定row2,并且由于先前的锁定,SQL服务器等待
因此,SQL服务器必须选择事务,杀死它,并允许另一个继续。
此图片很好地说明了这种情况:http://www.eupodiatamatando.com/wp-content/uploads/2008/01/deadlocknajkcomafarialibh3.jpg