NOLOCK总是不好吗?


34

我是一个报表开发人员,想要使我的查询尽可能高效。我曾经和一个DBA一起工作,他告诉我-我相信是因为我一直在生产服务器上处理报表-可以NOLOCK在每个查询中使用。

现在,我与一个NOLOCK在任何情况下都被禁止使用的DBA一起工作-即使我的报告(由于在几个表上严重缺乏索引)正在停止复制和系统更新。我认为,在这种情况下,a NOLOCK将是一件好事。

由于我的大多数SQL培训都针对不同的DBA提出了截然不同的意见,因此我想向各种各样的DBA提出这一要求。


Answers:


30

如果您的报告阻止DBA正确的更新:您绝对不应使用NOLOCK。张女士说,有冲突清楚地表明,如果你用脏读,你会得到不正确的报告。

我认为,总有比NOLOCK以下更好的选择:

  • 您的生产表是否只读且没有被修改?将数据库标记为只读!
  • 表扫描会导致锁冲突?适当地索引表,好处是多方面的。
  • 无法修改/不知道如何正确编制索引?使用快照隔离
  • 无法将应用更改为使用快照?打开已读提交的快照
  • 您已经衡量了行版本控制的影响,并有证据证明行版本控制会影响性能吗?您无法索引数据?并且您可以接受错误的报告吗?然后至少要帮自己一个忙,并使用它SET TRANSACTION ISOLATION LEVEL,而不是查询提示。以后修复隔离级别而不是修改每个查询将更加容易。

6
注意:打开已读提交的快照可能会破坏一些代码。
AK 2012年

33

这并不总是坏的。

当然,它允许您读取未提交的值(这些值可能会回滚,因此从逻辑上讲是不存在的),以及允许出现多次读取值或根本不读取值的现象。

唯一可确保您不会遇到此类异常的隔离级别是可序列化/快照。如果在扫描到达此行之前移动了行(由于更新了键),则在可重复读值不足的情况下会丢失;如果键更新导致先前读取的行向前移动,则读未提交的值可被读取两次。

nolock但是,由于在默认情况下,在此隔离级别下,当估计要读取的页数超过64页时,它将使用分配排序的扫描,因此很可能会出现这些问题。以及由于索引键更新导致行在页面之间移动时出现的问题类别,这些分配排序的扫描也容易受到页面拆分问题的影响(如果新分配的页面在文件中早于该点,则行可能会丢失)已扫描或读取两次(如果已扫描的页面在文件中拆分为下一页)。

至少对于简单(单表)查询,可以nolock通过简单ORDER BY index_key地在查询中添加an ,从而使is 的Ordered属性阻止使用这些扫描并获得键排序的扫描。IndexScantrue

但是,如果您的报表应用程序不需要绝对精确的数字,并且可以容忍这种不一致的可能性更大,则可以接受。

但是,当然,您不应该在所有查询上都放弃它,希望它是一个神奇的“ turbo”按钮。在该隔离级别遇到异常结果的可能性更大,或者根本没有结果(“由于数据移动而无法继续使用NOLOCK进行扫描”错误),甚至在某些情况下,其性能nolock 可能会更差


3
+1-我们经常使用它,因为生产表永远都不会被修改。
JNK 2012年

@JNK是什么意思,永远不会被修改?
Kuberchaun 2012年

4
马丁,我会提出一些稍微不同的词:“在读入的承诺值下,既可能会遗漏又会读不止一次”。在某些特殊情况下,我们可以使行被检索两次以上。
2012年

@ StarShip3000对于最终用户,我们部署到生产中的数据基本上是只读的,因此他们的大多数视图都具有NOLOCK提示
JNK

11

您的客户可以容忍报告中的不一致结果吗?如果答案是否定的,则不应使用NOLOCK-在并发下可能会得到错误的结果。我在这里这里这里写了一些例子。这些示例在READ COMMITTED和REPEATABLE READ下显示不一致的输出,但是您可以对其进行调整,并使用NOLOCK得出错误的结果。


我创建的大多数报告都不会在当前数据上运行。大多数客户的运行报告是昨天的数据。如果是这样,您的答案会改变吗?
DataGirl 2012年

8

我创建的大多数报告都不会在当前数据上运行。大多数客户的运行报告是昨天的数据。如果是这样,您的答案会改变吗?

如果是这种情况,那么您还有一个可能的选择:您可以在生产数据库的副本中运行报表,
而不是在生产数据库上运行查询并弄乱锁和NOLOCK,而无需执行任何操作。

您可以对其进行设置,以便每晚自动从备份中还原它
显然,您的报告在客户站点上的服务器上运行,因此我不知道设置此设置是否对您而言是可行的解决方案。
(但是再说一次……无论如何,它们都应该有备份,因此您只需要一些服务器空间即可还原它们)

我是内部开发人员,因此对我来说比较容易,因为我可以完全控制服务器和数据库。

您至少可以对仅需要昨天和更早的数据的报告执行此操作。也许某些报告必须保留在生产数据库中,但是至少您将部分负载移至另一个数据库(甚至更好的是,另一个服务器)。

我在工作中也
遇到相同的情况:我们几乎将所有此类报表使用这样的生产数据库副本,但是有一些查询需要今天的数据。


我喜欢您的回答,如果我能完全控制的话,它会奏效,但我没有。很多时候,我没有完全控制权,也无法创建索引。如果能够运行/显示执行计划,我很幸运。
DataGirl 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.