SQL Server 2008:获取死锁......没有任何锁定

时间:2011-03-28 21:14:50

标签: sql-server concurrency deadlock

我目前正在SQL Server 2008数据库上进行一些实验。更具体地说,我有一个JDBC应用程序,它使用数百个并发线程来执行数千个任务,每个任务在数据库上运行以下查询:

UPDATE from Table A where rowID='123'

但是,每当我将隔离级别设置为高于READ_UNCOMMITTED时,我就会遇到大量的死锁错误(SQL异常1205)。即使我设置了行锁定,表锁定和独占锁定提示,它也会发生!即使在不使用锁的快照隔离中,我仍然会遇到死锁错误。

我通过SQL事件探查器运行了一个跟踪,以便在发生这种情况时获取死锁图,但它并没有多大用处。它显示受害者进程连接到“线程池”,连接到数百个其他进程。你可以在这里查看:

http://i.stack.imgur.com/7rlv3.jpg

有没有人知道为什么会这样?过去几天我一直在疯狂地试图解决这个问题。我目前的假设是它与我的数据库实例中的可用工作线程,可用内存量或与实际查询级别锁无关的东西相关。

谢谢!

3 个答案:

答案 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)

像这样的死锁/锁很奇怪,指向SQL服务器之外的东西。值得一提的是,我们遇到了很多死锁问题,结果证明是磁盘瓶颈!

我建议你运行perfmon(显然在那之后有很多其他工具)并看看它是如何做的。

答案 2 :(得分:1)