NOLOCK (Sql Server 提示)是不好的实践吗?

我的业务是制作网站和应用程序,这是 没有任务的关键-> 银行软件,太空飞行,重症监护监测应用程序等。你懂的。

那么,在某些 Sql 语句中使用 NOLOCK 提示是否不好呢?几年前,一位 Sql 管理员建议,如果我对“脏读”感到满意,那么我应该使用 NOLOCK,因为每次读都不会锁定表/行/随便什么。

我还被告知,如果我遇到死锁,这是一个很好的解决方案。因此,我开始跟随这个想法几年,直到一位 Sql 专家帮助我处理一些随机代码,并注意到我的 Sql 代码中的所有 NOLOCKS。我受到了礼貌的斥责,他试图向我解释(为什么这不是一件好事) ,我有点迷路了。我觉得他解释的本质是“这是对一个更严重问题的权宜之计。”。.特别是当你遇到死锁的时候。因此,解决问题的根源’。

我最近在谷歌上搜索了一下,发现了 这篇文章

那么,能不能请一些 sql db 的大师老师来指点我一下?

114987 次浏览

如果您不关心脏读(例如,在一个主要是读的情况下) ,那么 NOLOCK是好的。

但是请注意,大多数锁定问题都是由于没有为查询工作负载提供“正确的”索引(假设硬件能够胜任这项任务)造成的。

大师的解释是正确的,这通常是对更严重问题的权宜之计。

编辑 : 我绝对不建议使用 NOLOCK。我想我应该说得很清楚。(我只会在极端情况下使用它,因为我已经分析过它是可以的)。作为一个例子,前一阵子我在一些 TSQL 上工作,这些 TSQL 已经使用了 NOLOCK 来试图减轻锁定问题。我删除了它们,实现了正确的索引,所有的死锁都消失了。

使用 NOLOCK 提示,SELECT语句的事务隔离级别为 READ UNCOMMITTED。这意味着查询可能会看到脏的和不一致的数据。

这不是一个适用于规则的好主意。即使这种脏读行为对你的任务关键网络应用程序是可以的,一个 NOLOCK 扫描可能会导致601错误,这将终止查询由于数据移动缺乏锁定保护的结果。

我建议阅读 什么时候快照隔离有用,什么时候疼-MSDN 推荐在大多数情况下使用 READ COMMITTED SNAPSHOT 而不是 SNAPSHOT。

在研究 Stack Overflow 之前,我曾反对使用 NOLOCK执行 SELECT并返回带有可能过期或不一致的数据的结果。需要考虑的一个因素是在同一时间可以插入/更新多少条记录,另一个进程可能从同一表中选择数据。如果这种情况经常发生,那么死锁的概率很高,除非您使用 READ COMMITED SNAPSHOT这样的数据库模式。

在目睹了 NOLOCK如何提高 SELECT性能以及消除大量加载的 SQL Server 上的死锁之后,我改变了自己对使用 NOLOCK的看法。有些时候,您可能并不关心数据没有完全提交,并且您需要快速返回结果,即使它们可能已经过时。

当考虑使用 NOLOCK时,问自己一个问题:

我的查询是否包含一个具有大量 INSERT/UPDATE命令的表? 我是否关心查询返回的数据是否在给定时刻缺少这些更改?

如果答案是否定的,那么使用 NOLOCK来提高性能。


我刚刚在 Stack Overflow 的代码库中快速搜索了 NOLOCK关键字,发现了138个实例,所以我们在很多地方使用了它。

没有一个答案是错的,尽管可能有点令人困惑。

  • 在查询单个值/行时,使用 NOLOCK 是 一直都是的错误做法——您可能永远不想显示不正确的信息,甚至可能不想对不正确的数据采取任何行动。
  • 在显示粗略的统计信息时,NOLOCK 非常有用。以 SO 为例: 用锁来读取一个问题的 一模一样视图数,或者一个标签的确切问题数,都是没有意义的。现在没有人关心您是否错误地陈述了标记为“ sql-server”的3360个问题,并且由于事务回滚,一秒钟之后就会出现3359个问题。

我怀疑这是一个“大师”谁有任何经验,在高流量..。

网站通常是“肮脏”的时候,人们正在查看完全加载的网页。考虑一个从数据库加载然后保存已编辑的数据的表单?人们总是说黄色读物是不可以的,这太愚蠢了。

也就是说,如果您有一些层建立在您的选择,您可能会建立在一个危险的冗余。如果您处理的是金钱或状态场景,那么您不仅需要事务性数据读/写,还需要一个适当的并发解决方案(大多数“大师”都不关心这个)。

另一方面,如果你有一个先进的产品搜索网站(即可能不会缓存和有点密集的东西) ,你曾经建立了一个网站,并发用户超过几个(惊人的多数“专家”没有) ,这是荒谬的瓶颈后面的每一个过程。

知道它的意思,并在适当的时候使用它。如今,您的数据库几乎总是您的主要瓶颈,聪明地使用 NOLOCK 可以为您节省数以千计的基础设施。

编辑: 它不仅有助于解决死锁问题,还可以让其他人等到你完成,反之亦然。

在 EF4中使用 NOLOCK 提示?

作为一个专业的开发人员,我得说这要看情况。但我绝对遵循 GATS 和 OMG 小马的建议。知道你在做什么,知道什么时候有帮助,什么时候有伤害

暗示和其他糟糕的想法

什么可能使您更深入地理解 sql 服务器。我通常遵循 SQL 提示是 EVIL 的规则,但不幸的是,当我受够了强制 SQL 服务器执行某些操作时,我会时不时地使用它们... ... 但这种情况很少见。

Luke

当 app-support 想要使用 SSMS (不是通过报告满足的)来回答来自生产服务器的 ad-hock 查询时,我请求他们使用 nolock。这样,“主要”业务就不会受到影响。

我同意一些关于 NOLOCK 提示的评论,特别是那些说“在适当的时候使用它”的评论。 如果应用程序写得很糟糕,并且使用并发的方式不恰当,这可能会导致锁升级。高度事务性的表由于其本质也一直处于锁定状态。具有良好的索引覆盖率无助于检索数据,但是将 ISOLATION LEVEL 设置为 READUNCOMMITTED 有助于检索数据。 另外,我相信在很多情况下使用 NOLOCK 提示是安全的,因为更改的性质是可预测的。例如,在制造过程中,当旅行者的工作要经历不同的过程,需要大量的测量插入时,你可以安全地使用 NOLOCK 提示对完成的工作执行查询,这样就可以避免与其他会话发生冲突,这些会话会将 PROMOTED 或 EXEXLEIVE 锁放在表/页面上。在这种情况下,您访问的数据是静态的,但是它可能位于一个事务性很强的表中,每分钟有数亿条记录和数千次更新/插入。 干杯

如果可能的话,更好的解决办法是:

  • 将数据复制(使用日志复制)到报表数据库。
  • 使用 SAN 快照并挂载数据库的一致版本
  • 使用基本事务隔离较佳的资料库

SNAPSHOT 的事务隔离级别是因为微软正在输给甲骨文。Oracle 使用撤销/重做日志来避免这个问题。Postgres 使用 MVCC。在未来,微软的 Heckaton 将使用 MvCC,但是距离投产还有好几年的时间。

我认为使用 nolock 实际上从来都是不正确的。

如果您正在读取单个行,那么正确的索引意味着您不需要 NOLOCK,因为单个行操作很快就完成了。

如果您正在为临时显示以外的任何内容读取许多行,并且关心能否重复结果,或者通过产生的数字进行防御,那么 NOLOCK 是不合适的。

NOLOCK 是一个替代标记,表示“我不在乎这个答案是否包含重复的行、被删除的行,或者因为回滚而从未插入的行”

在 NOLOCK 下可能出现的错误:

  • 根本不返回匹配的行。
  • 将多次返回单行(包括同一主键的多个实例)
  • 返回不匹配的行。

在 noLock 选择运行时,任何可能导致页分割的操作都可能导致这些情况发生。几乎任何操作(甚至是删除操作)都可能导致分页。

因此: 如果您“知道”在运行时行不会被更改,那么不要使用 nolock,因为索引将允许有效的检索。

如果您怀疑在查询运行时行可能会发生更改,并且您关心准确性,那么不要使用 nolock。

如果因为死锁而考虑使用 NOLOCK,请检查查询计划结构以查找意外的表扫描,跟踪死锁并查看它们发生的原因。围绕写操作的 NOLOCK 可能意味着以前死锁的查询可能都写错了答案。

NOLOCK 经常被用作加快数据库读取速度的神奇方法,但我尽可能避免使用它。

结果集可以包含尚未提交的行,这些行通常在以后回滚。

错误或结果集可以为空、缺少行或多次显示同一行。

这是因为其他事务在读取数据的同时也在移动数据。

READCOMMITTED 增加了一个额外的问题,即数据在单列中损坏,多个用户同时更改同一个单元格。

在现实生活中,当你遇到已经编写好的系统,并且为表添加索引,然后大大减慢了14G 数据表的数据加载速度时,你有时不得不在报表和月底处理中使用 WITHNOLOCK,这样聚合函数(sum,count 等)就不会执行行、页面、表锁定并降低整体性能。 说起来容易,在新系统中永远不要使用 WITHNOLOCK 和使用索引——但是添加索引会严重降低数据加载的等级,当我被告知,好吧,改变代码基来删除索引,然后批量加载,然后重新创建索引——如果你正在开发一个新系统,这是非常好的。但如果你已经有了一套系统就不会了。