如何重现“由于数据移动,无法继续使用 NOLOCK 扫描”

woo*_*e23 10 sql-server sql-server-2008-r2 nolock

我偶尔会NOLOCK在一些大型作业中遇到“由于数据移动而无法继续扫描”,这些作业WITH (NOLOCK)在选择查询中确实有。

我知道这与在页面拆分导致数据不再位于应有的位置时尝试选择数据有关 - 我认为这就是我的环境中发生的情况。

我将如何重现这个?

我正在尝试做一个短期的解决方法来捕捉错误并在发生这种情况时重试,但如果我无法重现它,我将无法对其进行测试。有没有合理可靠的方法来导致这种情况?

当它发生时,再次执行查询会导致成功 - 所以我真的不担心实际数据或数据库被永久损坏。查询中的一些表(连同它们的索引)经常被删除、重新创建和重新填充,所以我假设它与此相关。

移除NOLOCK是我要处理的长期问题。NOLOCK放在那里的原因首先是查询非常糟糕,以至于它们因日常事务而陷入僵局,因此可以NOLOCK使用创可贴来阻止僵局(有效)。所以我需要一个创可贴,直到我们可以做一个永久性的解决方案。

如果我可以用 Hello World 重现它,我可能会计划在不到一个小时的时间内将创可贴贴到工作中。无法执行搜索和替换删除NOLOCK,因为我会再次开始使应用程序陷入僵局,这对我来说比偶尔失败的工作更糟糕。

使用读提交的快照隔离是一个很好的可能性 - 我将不得不与我们的数据库团队合作以获取更多详细信息。我们的部分问题是我们没有 SQL Server 专家来处理这类事情,而且我对隔离级别的了解还不够充分,无法立即进行更改。

RLF*_*RLF 8

由于解决 NOLOCK 问题的一个潜在“创可贴”是停止使用 NOLOCK 并开始使用 READ_COMMITTED_SNAPSHOT 隔离,因此我想向您指出Kendra Little在http://www.brentozar.com上的博客文章:Implementing Snapshot or Read Committed SQL Server 中的快照隔离:指南

Kendra 提供了大量有关使用 READ_COMMITTED_SNAPSHOT 隔离级别的好处和风险的详细信息。

  1. 此隔离级别成为数据库代码的默认隔离级别。
  2. 您必须在数据库中只有一个用户才能更改 READ_COMMITTED_SNAPSHOT 隔离级别。
  3. 即使您使用 READ_COMMITTED_SNAPSHOT 隔离,您仍然需要删除 NOLOCK 提示,因为它们会覆盖默认值。
  4. 您的某些代码可能存在需要修复的问题。

几年前,我们实现了在一个数据库上READ_COMMITTED_SNAPSHOT隔离严重阻塞。但是一旦我们改变了隔离级别,我们就开始在几个关键区域陷入僵局

为什么会这样?因为之前的隔离级别导致了严重的阻塞,代码可能“永远”不会达到死锁点。但是,通过 READ_COMMITTED_SNAPSHOT 隔离,查询可以继续前进。然而,一些不再等待的事务开始死锁。

幸运的是,我们的案例通过确定死锁点并调整几个表上的索引以具有更合理的列顺序而很快得到解决。这大大减少了我们的锁定问题。