【问题标题】:SQL Server 2008: Getting deadlocks... without any locksSQL Server 2008:遇到死锁......没有任何锁
【发布时间】:2011-03-28 21:14:49
【问题描述】:

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

UPDATE from Table A where rowID='123'

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

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

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

有人对为什么会发生这种情况有任何提示吗?在过去的几天里,我一直在发疯,试图弄清楚。我目前的假设是,它与我的数据库实例中可用的工作线程、可用内存量或与实际查询级锁无关的东西有关。

谢谢!

【问题讨论】:

  • Seen this already?你的更新声明有并行计划吗?
  • 您是说当READ_UNCOMMITTED 生效时这些死锁从不发生?对我来说,这将如何影响显示的 update 语句并不明显。
  • 哇!没想到在这么短的时间内反应这么大!在 READ_UNCOMMITTED 下仍然会发生死锁,但只有当有很多很多的并发线程(大约 1000 个)在进行时。对于含糊其辞,我深表歉意。

标签: sql-server concurrency deadlock


【解决方案1】:

你遇到了一个更深奥的野兽:资源死锁。您所拥有的线程不能生成子任务 (sys.dm_os_tasks) 来执行其工作,因为所有工作人员 (sys.dm_os_workers) 都很忙。反过来,忙碌的工作人员执行被受害者阻塞的任务,可能是在普通锁上。

我在这里看到了两个教训:

1) 您发布的 UPDATE 正在尝试并行。如果更新与您发布的完全一样,那么这意味着只有一件事:rowId 上没有索引。

2) 你已经在max worker threads 设置的上限上反弹了。难怪,考虑到您滥用客户端中的线程 (hundreds of concurrent threads to execute thousands of task) 并由于不需要的并行性而在服务器中将其相乘。

明智的设计会在真正的异步连接 (AsynchronousProcessing=true) 上使用异步执行 (BeginExecuteNonQuery) 并使用待处理请求池,因此它不会超过某个阈值。更有可能的是,您将通过table valued parameter 传入整批更新值,然后在单个语句中批量更新整组或行。我知道我所有的链接都是针对.Net的,不是针对Java的,我不在乎,您可以自己挖掘等效的Java功能。

因此,虽然您发现了如此深奥的僵局很有趣,但它之所以出现只是因为您的设计,嗯……糟透了。

【讨论】:

  • 我会为出色的分析 +1.. 但用 -1 缓和了这一点,我们可以说,交付吗?省略 2 个字左右会读起来……更好吗?
  • 感谢您的回复,莱姆斯。我知道设计很糟糕,但这是故意的!我正在做一个项目,该项目应该表明 1.) 存在不同的读取异常,具体取决于所选的隔离级别的类型,并显示 2.) 选择限制并发性的隔离级别的经验性能命中超过了必要的程度。无论如何,您的 cmets 确实有道理,我会进一步研究一下;至少你能够为我提供进一步阅读的方向:-)
  • @akwok:我明白了。考虑到 UPDATE 必须首先找到要更新的行,然后更新它们。 “查找”部分受隔离级别的影响。甚至 REPEATABLE_READ 也可以选择在高粒度锁定级别(页、表)进行扫描。第二件要考虑的事情是“更新”部分将与所有隔离级别下的另一个更新冲突,包括快照。此外,由于哈希冲突,不同行的更新会发生冲突:rusanu.com/2009/05/29/…
  • @akwok:至于过度并发级别对性能的影响,请听听:blogs.msdn.com/b/dbrowne/archive/2010/05/21/…
  • @Richard:我不喜欢小字体,我能说什么:) hulu.com/watch/10335/saturday-night-live-pet-chow
【解决方案2】:

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

我建议你运行 perfmon(显然之后还有很多其他工具),看看它是怎么做的。

【讨论】:

    【解决方案3】:

    在没有锁的情况下,您无法在 SQL Server 中执行任何操作 - 即使是带有 NOLOCK 语句的最基本查询也会发出架构锁,并且可能至少会发出几个页面锁。

    为了解决死锁,您需要获取 T1204 死锁跟踪(有关详细信息,请参阅Deadlock Troubleshooting, Part 1),它将列出死锁中涉及的确切锁和对象 - 这应该是足够的信息来弄清楚(使用适量的挠头)到底出了什么问题。

    在不完全了解死锁背后的原因的情况下更改隔离级别对我来说似乎有点危险......

    作为一种预感,这让我想起了几年前的一个问题——UPDATE 语句是否与SELECT 语句陷入僵局? (T1024 跟踪会告诉你这一点)你在rowID 上有一个非聚集索引吗?如果是这样,您可能想查看this MSDN article,特别是示例 6:非聚集索引。如果没有,请继续阅读该文章,因为它可能有助于解释一些其他相关的死锁场景,如果您需要帮助分析它,也可以发布 T1024 跟踪的结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多