我目前正在SQL Server 2008数据库上进行一些实验。更具体地说,我有一个JDBC应用程序,它使用数百个并发线程来执行数千个任务,每个任务在数据库上运行以下查询:
UPDATE from Table A where rowID='123'
但是,每当我将隔离级别设置为高于READ_UNCOMMITTED时,我就会遇到大量的死锁错误(SQL异常1205)。即使我设置了行锁定,表锁定和独占锁定提示,它也会发生!即使在不使用锁的快照隔离中,我仍然会遇到死锁错误。
我通过SQL事件探查器运行了一个跟踪,以便在发生这种情况时获取死锁图,但它并没有多大用处。它显示受害者进程连接到“线程池”,连接到数百个其他进程。你可以在这里查看:
http://i.stack.imgur.com/7rlv3.jpg
有没有人知道为什么会这样?过去几天我一直在疯狂地试图解决这个问题。我目前的假设是它与我的数据库实例中的可用工作线程,可用内存量或与实际查询级别锁无关的东西相关。
谢谢!
答案 0 :(得分:6)
你遇到了一个更深奥的野兽:资源僵局。你所拥有的是一个线程而不能产生子任务(sys.dm_os_tasks
)来执行它的工作,因为所有工人(sys.dm_os_workers
)都很忙。反过来,忙碌的工作人员执行受害者被阻止的任务,可能是在普通锁上。
我在这里看到两个课程带回家:
1)您发布的UPDATE正在尝试并行。如果更新与您发布的完全一致,则表示只有一件事:rowId
上没有索引。
2)您已在max worker threads
设置的上限上弹跳。难怪,考虑到您滥用客户端中的线程(hundreds of concurrent threads to execute thousands of task
)并由于不必要的并行性而在服务器中将其相乘。
合理的设计会在真正的异步连接(BeginExecuteNonQuery
)上使用异步执行(AsynchronousProcessing=true
)并使用待处理请求池,因此它不会超过某个阈值。更有可能的是,您将通过table valued parameter传递整批更新值,然后在单个语句中更新整批一批或多批行。我知道我的所有链接都是针对.Net而不是Java,我不在乎,你可以自己挖掘出相同的Java功能。
所以虽然有趣的是你发现了这样一个深奥的僵局,它只会出现,因为你的设计很好......很糟糕。
答案 1 :(得分:1)
我建议你运行perfmon(显然在那之后有很多其他工具)并看看它是如何做的。
答案 2 :(得分:1)