2009-09-21 57 views
114

我在做网站和应用程序的业务是而不是任务关键 - >例如。银行软件,太空飞行,重症监护应用等等。你明白了。NOLOCK(Sql Server提示)不好的做法?

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

我被告知,如果我遇到死锁,这是一个很好的解决方案。所以,我开始关注这个想法几年,直到一位Sql guru帮我一些随机代码,并注意到我的sql代码中的所有NOLOCKS。我被礼貌地责骂,他试图向我解释(为什么它不是一件好事),我总是迷失方向。我觉得他的解释的实质是“这是一个更严重问题的创可贴解决方案,尤其是如果你遇到了僵局。因此,解决问题的根源'。

我最近做了一些关于谷歌搜索,并跨越this post来了。

那么,可以一些sql db guru sensei的请赐教吗?

+0

我不明白Sam,如果它是一个繁重的阅读网站,请说使用快照隔离。但是,那么你说这么做,那很糟糕?或者只是使用NOLOCK? – 2009-09-21 11:47:14

回答

63

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

这不是一个好主意。即使您的任务关键型基于Web的应用程序的这种脏读取行为正常,NOLOCK扫描也会导致601错误,这将由于缺少锁定保护而导致数据移动而终止查询。

我建议阅读When Snapshot Isolation Helps and When It Hurts - MSDN的建议在大多数情况下使用读提交快照而不是快照。

+0

雷克斯,请随时添加关于快照隔离的说明。 – 2009-09-21 06:01:09

+2

是的,山姆说快照隔离,你建议读取提交快照。我很困惑:P(我还没有深入研究文章,也!) – 2009-09-21 11:49:11

+2

它偶尔有用,但通常不用于生产。我经常使用它来抽出一个数据样本来进行测试或生成报告,我主要关心粗略的数量级,在这种情况下,脏读无关紧要。 – TimothyAWiseman 2012-05-14 22:50:15

19

如果你不在乎脏读(即在主要阅读的情况),那么NOLOCK是罚款。

,要知道,大多数的锁定问题是由于没有“正确的”索引查询的工作量(假设硬件是完成这一任务)。

而古鲁的解释是正确的。对于更严重的问题,它通常是一种创可贴的解决方案。

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

+3

嗯..我还是不明白。所以这很好,但它也是一个糟糕的形式..是你在说什么? – 2009-09-21 05:41:15

+0

假设你从不关心脏读,那么它不会受到伤害。但它通常是治疗症状,而不是原因... – 2009-09-21 05:49:19

+2

嗯,我不认为它的公平rexem只是downvoted,我认为你没有解决任何错误,只是浮起来,当你使用nolock。在您的网站上偶尔会出现一个空白的错误页面并不好,它的确很糟糕。我不喜欢这样的断言:“如果你不在乎脏读取它的罚款”......即使你不在乎脏读 – 2009-09-21 05:55:46

95

在使用堆栈溢出之前,我的原则是针对NOLOCK,您可能会执行SELECTNOLOCK并获取可能过期或不一致的数据的结果。需要考虑的一个因素是可以同时插入/更新多少个记录,同时另一个进程可以从同一个表中选择数据。如果这种情况发生很多,那么除非使用数据库模式(如READ COMMITED SNAPSHOT),否则很有可能出现死锁。

因为我目睹了如何改进SELECT性能以及消除大容量加载的SQL Server上的死锁后,我改变了对NOLOCK的使用的看法。有时候,您可能并不在乎您的数据不完全是100%提交,即使它们可能已过期,也需要快速返回结果。

问自己一个问题使用NOLOCK的思考时:

难道我的查询包含有大量的INSERT/UPDATE命令的表,做我不在乎,如果从查询返回的数据可能会丢失这些变化在特定时刻?

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


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

+7

IMO,这有点简单。通过使用覆盖索引可以消除死锁,从集群索引中减去压力。 – 2009-09-21 06:27:49

+5

我不想减少良好指数覆盖的重要性。有些时候,使用NOLOCK的查询可以在大量插入/更新的表上通过索引实现的增益之外添加额外的性能。即使以不准确或缺失的数据为代价,Stack Overflow上的查询速度也是至关重要的。 – 2009-09-21 06:54:49

+0

谢谢让Geoff为答案。我需要消化它,但我一直在寻找一些关于如何从早期处理它们的僵局问题的答案。我从来没有读过他们研究或解决问题的任何“结果”,因为它。 – 2009-09-21 11:50:58

7

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

  • 当查询单值/排它总是不好的做法,使用NOLOCK - 你可能永远都不想显示不正确的信息,或者甚至采取不正确的数据采取任何行动。
  • 当显示粗略统计信息时,NOLOCK可能非常有用。以SO为例:使用锁来读取问题的数量或标签的确切问题数量将是无稽之谈。没有人在意你现在是否错误地陈述了3360个标有“sql-server”的问题,并且由于事务回滚,在一秒钟之后有3359个问题。
+0

我不同意你的第一点。如果您正在查询单个值/行,并且您正在为该行指定唯一的ID,并且您知道没有其他进程将访问它,那么使用nolock是完全可以接受的,并且可以减少并发应用程序中的阻塞。 – tuseau 2011-05-16 12:16:21

+0

不,它不是。该行可能因其他原因而改变,例如插入另一行来拆分页面。正确的索引,读取提交的快照和快照隔离几乎总是更好的想法。 – 2012-04-26 16:48:38

+0

@tuseau如果您“知道”没有其他进程访问该行,那么锁定行为不会阻止任何事情,因此您的(实际上)任何成本都没有, – 2016-04-18 04:55:59

13

疑问,这是一个“大师”谁喝了在高流量的经验......

网站通常是由时间“脏”的人观看完全加载页面。考虑从数据库加载的表单,然后保存编辑的数据?这是愚蠢的人们继续关于肮脏的阅读是这样的一个不行。

也就是说,如果您的选择有多个图层,那么您可能会构建一个危险的冗余。如果您在处理金钱或状态方面的问题,那么您不仅需要事务性数据读取/写入,而且还需要一个适当的并发解决方案(大多数“大师”并不打扰)。另一方面,如果您有一个先进的产品搜索网站(即可能不会缓存并且有点密集的东西),并且您曾经构建过一个网站,并且拥有多个并发用户(有多少“专家”没有),唾弃其后的所有其他流程是很荒谬的。

知道是什么意思,并在适当的时候使用它。现在你的数据库几乎总是你的主要瓶颈,而且使用NOLOCK可以为你节省成千上万的基础设施。

编辑:这不仅仅是它帮助的死锁,它还是你要让其他人等待多久才能完成,反之亦然。

Using NOLOCK Hint in EF4?

2

的专业开发我会说这要看情况。但我绝对遵循GATS和OMG Ponies的建议。知道你在做什么,知道什么时候它有助于当它伤害和

阅读hints and other poor ideas

什么能让你了解SQL服务器更深。我通常遵循SQL Hints是EVIL的规则,但不幸的是,当我厌倦了强迫SQL Server执行操作时,我偶尔会使用它们......但这些情况很少见。

卢克

2

当应用程序支持想回答使用SSMS(即不通过报告照顾)从生产服务器的广告,典当查询我要求他们使用NOLOCK。这样,“主要”业务不受影响。

2

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

1

的更好的解决方案,在可能的情况是:

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

快照事务隔离级别的形成是因为MS正在失去销售到Oracle数据库的版本一致。 Oracle使用撤销/重做日志来避免这个问题。 Postgres使用MVCC。未来,MS的Heckaton将使用MVCC,但距离生产准备还有几年的时间。

+0

上面有一个错字。我的意思是说“更好的基本事务隔离机制”。 – pwy 2014-02-07 22:37:27

+1

SNAPSHOT事务隔离级别是MS的发明。基本上它将数据放入TEMPDB的临时表中。该数据库在盒子上的所有数据库之间共享。所以,如果可能的话,您会希望将SSD用于TEMPDB。这可能比其他选项少。 – pwy 2014-02-07 23:08:29

2

我相信使用nolock几乎是不对的。

如果你正在读单行,那么正确的指数意味着,各行的操作快速完成你不需要NOLOCK。

如果你正在读许多行比临时显示其他什么,而在乎能重复的结果,或通过辩护产生的号码,然后NOLOCK是不恰当的。

NOLOCK是

错误这下是可能的,“如果这个答案包含重复行,行被删除,或从来没有插入开始,因为回滚与行我不在乎”的替代品标签NOLOCK:

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

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

因此:如果你“知道”,而你正在运行该行不会被改变,不NOLOCK使用,作为索引将允许高效的检索。

如果您怀疑查询运行时,该行可以改变,你在意的准确性,不要使用NOLOCK。

如果你正在考虑,因为死锁NOLOCK,检查意外表扫描查询计划结构,跟踪死锁,看看他们为什么会发生。写入周围的NOLOCK可能意味着先前死锁的查询可能会写出错误的答案。

0

NOLOCK经常利用为神奇方式来加快数据库中读取,但我会尽量避免使用它whever可能。

结果集可以包含尚未提交的行,这往往是后回滚。

错误或结果集可能为空,可能缺少行或多次显示相同的行。

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

READ COMMITTED添加其中的数据被多个用户同时改变相同的小区的单个列中损坏一个额外的问题。

-2

在你遇到已经写入系统和添加索引的表,然后急剧减慢一个14gig数据表的数据加载现实生活中,你有时不得不使用NOLOCK在您的报告和月proessing的结束,使得将使用的聚合函数(总和,计数等)不会执行行,页面,表锁定并降低整体性能。 在新系统中容易说,不要使用WITH NOLOCK并使用索引 - 但是添加索引会严重降级数据加载,并且当我被告知时,更改代码库以删除索引,然后批量加载然后重新创建索引 - 如果你正在开发一个新系统,这一切都很好。但是,当你有一个系统已经到位。