是NOLOCK(Sql Server提示)不好的做法吗?

时间:2009-09-21 05:21:11

标签: sql sql-server tsql sql-server-2008 nolock

我的业务是制作关键任务的网站和应用程序 - >例如。银行软件,太空飞行,重症监护应用等。你明白了。

所以,有了这个庞大的免责声明,在一些Sql语句中使用NOLOCK提示是不是很糟糕?几年前,一位Sql管理员建议我应该使用NOLOCK,如果我对“脏读”感到满意,这会让我的系统性能提高一些,因为每次读取都没有锁定表/行/不管。

我还被告知,如果我遇到死锁,这是一个很好的解决方案。所以,我开始关注这个想法几年,直到一个Sql大师帮我一些随机代码并注意到我的sql代码中的所有NOLOCKS。我被礼貌地骂了,他试图向我解释(为什么这不是一件好事)而且我迷路了。我觉得他的解释的本质是'它是一个解决更严重问题的创可贴解决方案......特别是如果你遇到了死锁。因此,修复问题的根源。

我最近做了一些谷歌搜索,并遇到了this post

那么,有些sql db guru sensei可以赐教吗?

12 个答案:

答案 0 :(得分:103)

在处理Stack Overflow之前,我反对委托人NOLOCK,可能会使用SELECT执行NOLOCK并获取可能已过期的数据的结果或不一致。要考虑的一个因素是可以在同一个表中选择数据的同时插入/更新多少记录。如果发生这种情况很多,那么除非您使用READ COMMITED SNAPSHOT等数据库模式,否则死锁的可能性很高。

在见证了如何提高NOLOCK性能以及消除大量加载的SQL Server上的死锁之后,我已经改变了对SELECT使用的看法。有时您可能并不关心您的数据是否完全100%提交,即使它们可能已过期,您也需要快速返回结果。

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

  

我的查询是否包含具有大量INSERT / UPDATE命令的表,我是否关心从查询返回的数据是否可能在给定时刻丢失这些更改?

如果答案为否,请使用NOLOCK来提高效果。

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

答案 1 :(得分:65)

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

这不适合作为规则应用。即使您的基于Web的关键任务应用程序的脏读行为正常,NOLOCK扫描也可能导致601错误,由于缺少锁定保护而导致数据移动,这将终止查询。

我建议阅读When Snapshot Isolation Helps and When It Hurts - 在大多数情况下,MSDN建议使用READ COMMITTED SNAPSHOT而不是SNAPSHOT。

答案 2 :(得分:20)

如果您不关心脏读(即主要处于READ状态),那么NOLOCK就可以了。

,请注意大多数锁定问题是由于查询工作负载没有“正确”索引(假设硬件完成任务)。

大师的解释是正确的。它通常是解决更严重问题的创可贴解决方案。

编辑:我绝对不建议使用NOLOCK。我想我应该明白这一点。 (我只会在极端情况下使用它,我已经分析过它可以)。作为一个例子,前一段时间我在一些TSQL上工作,这些TSQL上撒有NOLOCK以试图缓解锁定问题。我删除了它们,实现了正确的索引,所有的死锁都消失了。

答案 3 :(得分:13)

怀疑这是一个“大师”谁有高流量的经验......

当用户查看完整加载的页面时,网站通常会“脏”。考虑一个从数据库加载然后保存编辑的数据的表单?人们继续谈论肮脏的阅读是不可能的,这是愚蠢的。

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

另一方面,如果您有一个高级产品搜索网站(即可能不会被缓存并且有点密集的东西)并且您曾经构建过一个具有多个并发用户的网站(现象中有多少“专家”没有),它背后的每一个过程都是瓶颈。

了解它的含义并在适当的时候使用它。如今,您的数据库几乎总是您的主要瓶颈,并且使用NOLOCK的智能可以为您节省数千个基础设施。

编辑:这不仅仅是它所帮助的死锁,也是你要让其他人等到你完成的时间,反之亦然。

Using NOLOCK Hint in EF4?

答案 4 :(得分:9)

没有一个答案是错的,但也许有点混乱。

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

答案 5 :(得分:2)

作为一名专业开发人员,我认为这取决于。但我绝对遵循GATS和OMG小马的建议。知道你在做什么,知道什么时候有帮助,什么时候疼,

阅读hints and other poor ideas

可能会让您更深入地了解sql server。我通常遵循SQL提示是EVIL的规则,但不幸的是我不时地使用它们当我厌倦了强迫SQL服务器做事情......但这些情况很少见。

答案 6 :(得分:2)

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

答案 7 :(得分:2)

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

答案 8 :(得分:2)

我认为使用nolock几乎是不正确的。

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

如果您正在阅读除临时显示之外的任何行,并且关心能够重复结果,或者通过产生的数字进行辩护,那么NOLOCK是不合适的。

NOLOCK是“我不关心这个答案是否包含重复的行,删除的行,或者因为回滚而从未插入过的行”的代理标记

在NOLOCK下可能出现的错误:

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

任何在noLock select运行时可能导致页面拆分的操作都可能导致这些事情发生。几乎任何动作(甚至是删除)都可能导致页面拆分。

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

如果您怀疑在查询运行时行可以更改,并且您关心准确性,请不要使用nolock。

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

答案 9 :(得分:1)

更好的解决方案,如果可能的话:

  • 将数据(使用日志复制)复制到报告数据库。
  • 使用SAN快照并安装DB的一致版本
  • 使用具有更好基本事务隔离级别的数据库

创建了SNAPSHOT事务隔离级别,因为MS正在失去对Oracle的销售。 Oracle使用撤消/重做日志来避免此问题。 Postgres使用MVCC。未来MS的Heckaton将使用MVCC,但距离生产准备还有几年的时间。

答案 10 :(得分:1)

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

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

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

这是因为其他交易在您阅读的同时正在移动数据。

READ COMMITTED增加了一个额外的问题,即单个列中的数据被破坏,其中多个用户同时更改同一个单元格。

答案 11 :(得分:-2)

在现实生活中遇到已经编写的系统并向表中添加索引然后大大减慢了14gig数据表的数据加载速度,有时你被迫在报告中使用WITH NOLOCK并在月末进行处理以便聚合功能(总和,计数等)不执行行,页,表锁定并确定整体性能。 在新系统中很容易说,从不使用WITH NOLOCK并使用索引 - 但是添加索引会严重降低数据加载的速度,然后我告诉他们,改变代码库以删除索引,然后批量加载然后重新创建索引 - 如果你正在开发一个新系统,这一切都很好。但是当你已经有一个系统时就不行了。