2009-06-01 148 views
1

在生产SQL Server 2000数据库中,我们遇到了一些非常烦人的死锁情况。SQL Server 2000死锁

主要设置如下:

  • SQL Server 2000企业版。
  • 服务器使用ATL OLE数据库以C++编码。
  • 通过存储过程访问所有数据库对象。
  • 所有UPDATE/INSERT存储过程都将其内部操作包装在BEGIN TRANS ... COMMIT TRANS块中。

我收集与SQL事件探查继互联网就像this one上几篇文章了一些初步的痕迹(忽略它指的是SQL Server 2005和的工具,同样的原则也适用)。 从跟踪看来,它是两个UPDATE查询之间的死锁。

我们已经采取可能从作为发生降低问题的可能性了一些措施:

  • 选择带(NOLOCK)。我们更改了存储过程中的所有SELECT查询以使用WITH(NOLOCK)。我们理解具有脏读取的含义,但被查询的数据并不重要,因为我们会进行大量自动刷新,并且在正常情况下,UI将具有正确的值。
  • READ UNCOMMITTED。我们已将服务器代码上的事务隔离级别更改为READ UNCOMMITED。
  • 交易范围缩小。我们减少了交易的时间,以尽量减少发生数据库死锁的可能性。

我们也在质疑我们在大多数存储过程(BEGIN TRANS ... COMMIT TRANS块)内部有一个事务。在这种情况下,我猜测事务隔离级别是SERIALIZABLE,对吗?那么如果我们在调用存储过程的源代码中指定了事务隔离级别(如果我们也有),哪一个适用?

这是一个处理密集型应用程序,我们正在为读取(更大的百分比)和一些写入命中数据库。

如果这是一个SQL Server 2005数据库,我可以用Geoff Dalgas answer on an deadlock issue concerning Stack Overflow,如果这甚至适用于我遇到的问题。但是,升级到SQL Server 2005目前还不是一个可行的选择。我的问题是:你会怎么走?您会采取哪些步骤来减少甚至避免发生死锁,或者我应该使用哪些命令/工具来更好地揭示问题?

回答

0

在我的设置方案中死锁的原因是在所有索引之后。我们正在使用(默认生成)non clustered索引表的主键。更改为clustered索引解决了问题。

+0

它看起来像只是影响了一些时间,巧合得到了减少相同死锁的机会。 – 2009-11-27 20:31:43

1

几点意见:

  1. 在存储过程中明确指定的隔离级别覆盖主叫的isolatlation水平。

  2. 如果sp_getapplock可在2000年,我会使用它:

    http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx

  3. 在许多情况下,序列化隔离级别增加你会得到一个僵局的机会。

  4. 2000年良好的资源:

    http://www.code-magazine.com/article.aspx?quickid=0309101&page=1

还有些巴特邓肯的建议可能适用:

http://blogs.msdn.com/bartd/archive/2006/09/09/747119.aspx

0

除了Alex的答案:

  • 检查代码以查看是否按相同顺序访问表。我们最近做了这件事,并重新将代码重新排序,以便继续为父母和孩子。系统已经发展壮大,代码和功能更复杂,用户更多:我们只是开始陷入僵局。

- 看看交易可以被缩短(如后,完成较早,处理少开始)

  • 确定你想不失败,使用SET DEADLOCK优先级低,其中的代码另一个 我们已经使用过了(SQL 2005在这里有更多的选项),以确保某些代码永远不会死锁并牺牲其他代码。

  • 如果您在事务开始时有SELECT准备某些内容,请考虑HOLDLOCK(也许UPDLOCK)在此期间保持锁定状态。我们偶尔使用这个,所以不要在其他进程上写入这个表。

0

我的猜测是,你正在经历死锁,或者:

  1. 因为你的DML(更新可能)语句越来越上报到表锁,或
  2. 不同的存储过程访问交易中的相同表格但顺序不同。

为了解决这个问题,我将首先检查存储过程,并确保修改语句具有他们需要的索引。

注意:这适用于目标表和源表(尽管NOLOCK,UPDATE的源表也会获得锁。请检查用户存储过程中的扫描查询计划。与批处理或批量操作不同,大多数用户查询& DML在表行的一小部分子集上工作,因此不应锁定整个表。

然后,我会检查存储过程以确保存储过程中的所有数据访问都按照一致的顺序完成(父 - >子通常是首选)。