我目前正在 SQL Server 2008 数据库上进行一些实验。更具体地说,我有一个 JDBC 应用程序,它使用数百个并发线程来执行数千个任务,每个任务都在数据库上运行以下查询:
UPDATE from Table A where rowID='123'
但是,每当我将隔离级别设置为高于 READ_UNCOMMITTED 时,我都会收到大量死锁错误(SQL 异常 1205)。即使我设置了行锁定、表锁定和独占锁定提示,也会发生这种情况!即使在不使用锁的快照隔离中,我仍然会遇到死锁错误。
我通过 SQL Profiler 进行了跟踪,以获取发生这种情况时的死锁图,但这并没有多大用处。它显示了受害者进程,连接到“线程池”,连接到数百个其他进程。您可以在这里查看:
https://i.stack.imgur.com/7rlv3.jpg https://i.stack.imgur.com/7rlv3.jpg
有谁有任何提示为什么会发生这种情况?在过去的几天里,我一直在疯狂地试图找出答案。我当前的假设是,它与数据库实例中的可用工作线程、可用内存量有关,或者与实际查询级锁无关。
Thanks!
你遇到了一个更深奥的野兽:资源死锁。你所拥有的线程无法生成子任务(sys.dm_os_tasks http://msdn.microsoft.com/en-us/library/ms174963.aspx)执行其工作,因为所有工人(sys.dm_os_workers http://msdn.microsoft.com/en-us/library/ms178626.aspx)很忙。反过来,忙碌的工作人员执行被受害者阻止的任务(可能是在普通锁上)。
我在这里看到两个教训值得带回家:
1)您发布的更新正在尝试并行。如果更新与您发布的完全相同,那么这意味着一件事:没有索引rowId
.
2) 你已经在设定的上限上弹跳了max worker threads http://msdn.microsoft.com/en-us/library/ms187024.aspx环境。毫不奇怪,考虑到您滥用客户端中的线程(hundreds of concurrent threads to execute thousands of task
)并由于不需要的并行性而在服务器中将其相乘。
明智的设计将使用异步执行(BeginExecuteNonQuery http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.beginexecutenonquery.aspx)在真正的异步连接上(AsynchronousProcessing=true http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder.asynchronousprocessing.aspx)并使用待处理请求池,使其不会超过某个阈值。更有可能的是,您将通过表值参数 http://msdn.microsoft.com/en-us/library/bb510489.aspx然后在一条语句中批量更新整个集合或行。我知道我的所有链接都是针对.Net的,而不是针对Java的,我不在乎,你可以自己挖掘出等效的Java功能。
因此,虽然有趣的是您发现了如此深奥的僵局,但它之所以出现只是因为您的设计,嗯……很糟糕。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)