在我的情况下,With(NoLock) 提示是不是危险?

Posted

技术标签:

【中文标题】在我的情况下,With(NoLock) 提示是不是危险?【英文标题】:Is the With(NoLock) hint dangerous in my case?在我的情况下,With(NoLock) 提示是否危险? 【发布时间】:2015-12-15 19:32:19 【问题描述】:

我之前已经多次阅读和使用 with(nolock) 提示,但我对特定案例有疑问。

就我而言,我有一组引用和更新一个数据库的代码。 此代码旨在以单线程方式运行。 几个月前,他们决定在不更改代码的情况下使其成为多线程。他们的做法是让每个不同的“代码处理器”管理不同的商店组。

例如,处理器 1 负责存储 1 到 20,处理器 2 负责存储 21 到 40,依此类推。

在我们开始陷入僵局之前,一切似乎都很好。死锁总是在页面上......如果锁只在行上,我们将永远不会出现死锁,因为来自一个处理器的数据永远不会与来自另一个处理器的数据发生冲突。基于这个理论,我决定在每个不需要锁定的选择上加上 With(Nolock) 提示(还没有被放入 prod 中)......这使得我的死锁在我的实验室中消失了。

一切看起来都很好,直到我的同事用THIS 的文章来找我,这篇文章把我吓坏了...... 然后我读了THAT...

在我的情况下使用 With(Nolock) 提示是否存在危险...处理器之间的数据永远不会发生冲突?

【问题讨论】:

调查快照隔离。它消除了很多阻塞,并且比只读访问提交的读取更加一致。 【参考方案1】:

收回您的 nolock 提示并将您的数据库置于快照隔离级别。

READ_COMMITTED_SNAPSHOT 数据库选项开启

请参阅https://technet.microsoft.com/en-us/library/ms191242(v=sql.105).aspx 了解更多信息。但是,请注意,保存 tempDB 的磁盘在快照隔离中会遇到更高的 I/O。

【讨论】:

【参考方案2】:

是的,如果您收集的数据必须准确,则很可能会出现问题 - 您可能会抓取“脏”/不正确的数据,然后将其保留。您是否查看过索引是否可以改正死锁问题?通常可以通过控制对数据页的访问模式(由可用索引控制)来解决死锁情况。

我喜欢看死锁图看看哪里有冲突,然后看看代码中的操作顺序,哪些索引被用来访问/修改数据,看看能不能调整以消除死锁风险。

【讨论】:

我的理论是,在这种情况下读取脏数据应该不是问题,因为没有处理器接触来自另一个处理器的数据。第一篇文章让我害怕的是“缺少行”、“读取行两次”和“读取同一行的多个版本”。它是同时运行多次的相同代码。所以相同的索引会受到影响。因此,我遇到了很多死锁。大部分是一个 X 锁,最多 3 个 S 锁。通常 S 锁是受害者。 漏行、读两次、读多个版本都是脏数据的例子 对使用 RCSI 的建议也 +1。先测试,但实际上总是成功的。 读过之后,RCSI 好像不会在这里通过,因为我们需要修改属于客户的服务器上的 DB。我想我必须回到绘图板上,分析死锁中使用的索引。【参考方案3】:

看起来您的选择查询是死锁的原因。这就是可能发生的事情。您稍后可能会选择和更新记录。因此,当更新超过 5000 条记录时,sql server 使用锁升级并锁定整个表而不是锁定行。

如果你的程序是这样的 -

select .......
--some coding here----
update statement

如果另一个线程在你的更新语句之前使用了一个选择语句,你的更新语句将因为共享锁而被阻塞,你的更新语句将等待共享锁被释放,同时另一个进程发出更新语句。由于您应用了共享锁,第二个进程更新语句将被阻止。因此会发生死锁,因为两个线程都将相互等待。

解决方案-

    使用 UPDLOCK 提示 - 这将允许共享锁但不允许更新锁。将您的选择语句转换为 -> 使用 (UPDLOCK,ROWLOCK) 从 mytable 中选择 * RowLOCK 提示将在行级别而不是在页面或表级别保持锁定。这将减少死锁

    使用快照隔离

请注意不要在 select 语句中使用 with (NOLOCK),因为这会导致脏读,即未提交的数据,可能是错误的。

【讨论】:

我将与开发人员一起了解事件和交易的顺序。在我看来,在这个线程之前,With(nolock) 是一个可行的解决方案。我没有尝试过UPDLOCK但是当我尝试ROWLOCK提示时,我仍然看到一些页面锁定发生,这就是我没有追求的原因。理想情况下,ROWLOCK 提示可以解决我的所有问题,但不能确定会发生行锁定。

以上是关于在我的情况下,With(NoLock) 提示是不是危险?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Nolock 提示更新查询

SQL Server 中WITH (NOLOCK)

[SQL SERVER][Performance]小心使用With NoLock

通过在打开 READ_COMMITTED_SNAPSHOT 的 SQL Server 数据库上使用 WITH (NOLOCK) 是不是可以获得任何性能提升?

C# T-SQL 语句包含“with(nolock)”错误

Laravel Eloquent 和 Query Builder “with (nolock)”