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

7

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

UPDATE from Table A where rowID='123'

然而,每当我将隔离级别设置为高于READ_UNCOMMITTED时,我都会遇到大量死锁错误(SQL Exception 1205)。即使我设置了行锁定、表锁定和独占锁提示,这种情况仍会发生!即使在不使用锁的快照隔离中(Snapshot Isolation),我仍然会遇到死锁错误。
我通过SQL Profiler运行跟踪以获得死锁图形,但它没有太大用处。它显示了受害进程,连接到一个“线程池”,连接到数百个其他进程。你可以在这里查看它:

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

有人知道为什么会发生这种情况吗?我已经疯了几天了,试图找出原因。我目前的假设是与数据库实例中可用的工作线程、可用内存量或与实际查询级别锁无关的某些事物有关。

谢谢!


你看过这个吗?(http://blogs.msdn.com/b/bartd/archive/2008/09/24/today-s-annoyingly-unwieldy-term-intra-query-parallel-thread-deadlocks.aspx) 你的更新语句有并行计划吗? - Martin Smith
你是说当READ_UNCOMMITTED生效时,这些死锁就永远不会发生了吗?我并不明白这会如何影响所示的update语句。 - Martin Smith
哇!我没想到在这么短的时间内会有如此压倒性的反应!在READ_UNCOMMITTED下死锁仍然会发生,但只有在有很多、很多、很多并发线程时才会发生(大约1000个)。对于模糊不清表示歉意。 - akwok
3个回答

6
您遇到了一种更加深奥的问题:资源死锁。您所面对的是一个线程无法生成子任务(sys.dm_os_tasks)来执行其工作,因为所有工作线程(sys.dm_os_workers)都已忙碌。反过来,忙碌的工作线程会执行被阻塞的任务,很可能是普通锁定,被受害者所阻塞。
这里有两个需要注意的问题:
1)您发布的UPDATE尝试并行处理。如果更新正如您所发布的那样,则意味着只有一件事情:没有在rowId上建立索引。
2)您已经达到了max worker threads设置的上限。考虑到您在客户端滥用线程(数百个并发线程执行数千个任务),并在服务器上由于不必要的并行性而增加了这个数量,这并不奇怪。
一个明智的设计应该使用异步执行(BeginExecuteNonQuery)和一个真正异步的连接(AsynchronousProcessing=true),并使用一个挂起请求池,以便它不会超过某个阈值。更有可能的是,您将通过表值参数传递整个更新值批次,然后在单个语句中批量更新整个行集。我知道我所有的链接都是针对.Net的,而不是Java的,但我不在乎,您可以自己找到相应的Java功能。
因此,虽然您发现了这样一种深奥的死锁,但这只是因为您的设计...很糟糕。

1
我对你的精彩分析给予了+1,但是又因为交流方式的问题扣了-1。如果能省略掉两个词,读起来会更友好一些吧? - RichardTheKiwi
1
谢谢回复,雷莫斯。我知道这个设计很烂,但这是有意为之的!我正在做一个项目,旨在显示:1)不同的读取异常存在于选择的隔离级别类型取决,并显示2)选择限制并发性更多而不是必要的隔离级别会对实证性能造成影响。无论如何,你的评论很有道理,我会再深入研究一下;至少你为我提供了进一步阅读的方向 :-) - akwok
@akwok:我明白了。请考虑,UPDATE 首先必须找到要更新的行,然后再更新它们。'查找'部分受隔离级别影响。即使是 REPEATABLE_READ,也可以选择以高粒度锁定级别(页面、表)进行扫描。第二个需要考虑的事情是,在所有隔离级别下,包括快照,'更新'部分都会与另一个更新发生冲突。此外,由于哈希碰撞的原因,不同行的更新也会发生冲突:http://rusanu.com/2009/05/29/lockres-collision-probability-magic-marker-16777215/ - Remus Rusanu
@akwok:至于过度并发级别的性能影响,可以参考这篇文章:http://blogs.msdn.com/b/dbrowne/archive/2010/05/21/using-new-transactionscope-considered-harmful.aspx - Remus Rusanu
哦,关于Hulu的问题 - “抱歉,目前我们的视频库只能在美国境内流式传输。” 晚了一个赞(Belated +1)。 - RichardTheKiwi
显示剩余2条评论

1

这种死锁/锁定很奇怪,指向 SQL Server 外部的某些问题。值得一提的是,我们遇到了很多死锁问题,结果发现是磁盘瓶颈引起的!

我建议您运行 perfmon(当然,在此之后还需要运行许多其他工具)并查看其运行情况。


1

在SQL Server中,没有锁你就什么也做不了 - 即使是最基本的查询附加了NOLOCK语句也会发出模式锁,至少还会有一些页面锁。

为了解决死锁问题,需要获取T1204死锁跟踪(详见 Deadlock Troubleshooting, Part 1 ),它将列出死锁中涉及到的确切锁和对象 - 这应该足够的信息来找出(伴随适当的思考)出现问题的原因。

如果不完全理解死锁背后的原因就改变隔离级别,我觉得有点危险...

就我的直觉而言,这让我想起了几年前遇到的一个问题 - UPDATE 语句是否与 SELECT 语句发生死锁?(T1024 跟踪将告诉您)并且您是否在 rowID 上有非聚集索引?如果是,则您可能需要查看 this MSDN article,特别是示例6:非聚集索引。如果没有,请仍然浏览该文章,因为它可能有助于解释其他相关的死锁场景,并在需要分析时发布 T1024 跟踪结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接