什么是与(nolock)"SQL Server?

有人能解释一下在查询中使用with (nolock)的含义吗?什么时候应该/不应该使用它?

例如,如果你有一个银行应用程序,有很高的事务率,在某些表中有很多数据,在什么类型的查询中nolock是可以的?在某些情况下,你是否应该总是使用它/永远不要使用它?

745603 次浏览

您可以在仅读取数据时使用它,并且并不真正关心是否可能返回尚未提交的数据。

它可以在读取操作上更快,但我不能确切地说快多少。

一般来说,我建议不要使用它——读取未提交的数据最多可能会有点混乱。

WITH (NOLOCK)相当于使用READ uncommitted作为事务隔离级别。因此,您可能会读取一个未提交的行,该行随后会被回滚,即从未进入数据库的数据。因此,虽然它可以防止读取被其他操作死锁,但也存在风险。在具有高交易率的银行应用程序中,它可能不是您试图用它解决的任何问题的正确解决方案。

当你可以接受“脏”数据时使用nolock。这意味着nolock也可以读取正在修改的数据和/或未提交的数据。

在高事务处理环境中使用它通常不是一个好主意,这就是为什么它不是查询的默认选项。

我过去常常检索“下一批”要做的事情。在这种情况下,具体是哪个项目并不重要,我有很多用户运行相同的查询。

如果您正在处理金融事务,那么您永远不会想要使用nolocknolock最好用于从有很多更新的大型表中进行选择,并且您不关心所获得的记录是否可能过期。

对于财务记录(以及大多数应用程序中的几乎所有其他记录),nolock可能会造成严重破坏,因为您可能会从正在写入的记录中读取数据,而得不到正确的数据。

另一种通常可以接受的情况是在报告数据库中,其中的数据可能已经老化,不会发生写入操作。但是,在这种情况下,管理员应该通过更改默认隔离级别在数据库或表级别设置该选项。

在一般情况下:当您非常确定可以读取旧数据时,您可以使用它。重要的是要记住它是很容易弄错。例如,即使在编写查询时没有问题,但您确定将来数据库中不会有什么变化使这些更新变得更重要吗?

我还想说,在银行应用程序或库存应用程序中可能是个好主意。或任何你考虑交易的地方。

我使用with (nolock)提示,特别是在SQLServer 2000数据库的高活动。我不确定在SQL Server 2005中是否需要它。我最近应客户端的DBA的请求在SQL Server 2000中添加了这个提示,因为他注意到有很多SPID记录锁。

我所能说的是,使用提示并没有伤害我们,似乎已经使锁定问题解决自己。那个特定客户的DBA坚持让我们使用这个提示。

顺便说一下,我处理的数据库是企业医疗索赔系统的后端,因此我们谈论的是许多连接中的数百万条记录和20多个表。我通常为连接中的每个表添加WITH (nolock)提示(除非它是派生表,在这种情况下,您不能使用该特定提示)

NOLOCK相当于READ UNCOMMITTED,但是微软说你不应该在UPDATEDELETE语句中使用它:

对于UPDATE或DELETE语句:此功能将在Microsoft SQL Server的未来版本中删除。避免在新的开发工作中使用此特性,并计划修改当前使用此特性的应用程序。

http://msdn.microsoft.com/en-us/library/ms187373.aspx

本文适用于SQL Server 2005,因此如果您使用的是该版本,则存在对NOLOCK的支持。为了保证你的代码不受未来的影响(假设你决定使用脏读),你可以在你的存储过程中使用这个:

# EYZ0

nolock提示合法使用的教科书示例是针对高更新OLTP数据库的报告采样。

举个热门的例子。如果美国一家大型商业银行想要每小时发布一份报告,寻找城市层面的挤兑的最初迹象,那么nolock查询可以扫描每个城市的现金存取款总和的交易表。对于这样的报告,由回滚更新事务引起的微小百分比的错误不会降低报告的价值。

简单的答案-当你的SQL没有改变数据时,你有一个可能干扰其他活动的查询(通过锁定)。

对于用于报告的任何查询,都值得考虑,特别是当查询花费的时间超过1秒时。

如果您有针对OLTP数据库运行的olap类型的报告,那么它尤其有用。

第一个要问的问题是“我为什么要担心这个?”根据我的经验,当人们处于“尝试任何东西”模式时,通常会出现捏造默认锁定行为,而这种情况下意外的结果并非不可能发生。通常情况下,这是一个过早优化的情况,并且很容易嵌入到应用程序中“以防万一”。重要的是要了解你为什么要这样做,它解决了什么问题,以及你是否真的有问题。

问题是什么更糟:

  • 死锁,或者
  • 一个错误的值?

对于金融数据库来说,死锁比错误的值更糟糕。我知道这听起来有点反,但听我说完。DB事务的传统示例是更新两行,从一行中减去一行,向另一行中添加一行。这是错误的。

在财务数据库中使用业务事务。这意味着为每个帐户添加一行。这些事务的完成和行的成功写入是极其重要的。

让账户余额暂时错误不是什么大问题,这就是一天结束的和解。由于同时使用两台atm机,比未从数据库中读取数据更有可能发生帐户透支。

也就是说,SQL Server 2005修复了大多数使NOLOCK成为必要的错误。因此,除非您使用的是SQL Server 2000或更早版本,否则不需要它。

< p > # EYZ0 < br > # EYZ0 < / p >

不确定为什么没有在数据库事务中包装金融事务(当您将资金从一个帐户转移到另一个帐户时—您不每次提交事务的一方—这就是显式事务存在的原因)。即使您的代码听起来对业务事务来说是脑死亡,但所有事务性数据库都有可能在发生错误或失败时执行隐式回滚。我觉得这个讨论超出了你的理解力。

如果您遇到了锁定问题,请实现版本控制并清理代码。

没有锁不仅返回错误的值,还返回虚记录和副本。

这是一个常见的误解,它总是使查询运行得更快。如果表上没有写锁,也没有什么区别。如果表上有锁,它可能会使查询更快,但最初发明锁是有原因的。

公平地说,这里有两个特殊的场景,nolock提示可以提供实用程序

1) 2005年以前的sql server数据库需要对实时OLTP数据库运行长查询,这可能是唯一的方法

2)写得很糟糕的应用程序,它锁定记录并将控制权返回给UI和阅读器,无限期地阻塞。如果应用程序无法修复(第三方等),数据库是2005年以前或版本无法打开,Nolock可以在这里提供帮助。

我的意见-当你需要生成报告时,使用WITH (NOLOCK是有意义的。此时,数据不会有太大变化&你不会想要锁定这些记录的。

不幸的是,这不仅仅是读取未提交的数据。在后台,您可能会读两次页面(在页面分割的情况下),或者您可能会完全错过这些页面。所以你的结果可能是严重扭曲的。

看看Itzik Ben-Gan的文章。以下是节选:

"与NOLOCK提示(或设置 会话的隔离级别为READ UNCOMMITTED)你告诉SQL Server 你不期望一致性,就是这样 都不能保证。但是请记住 “不一致的数据”不仅 意味着你可能会看到uncommitted 后来被回滚的更改, 或者中间的数据变化 事务的状态。< >强也 意味着在一个简单的查询中 扫描所有的表/索引数据SQL Server 可能会失去扫描的位置,还是你 可能会得到同一行 < / >强两倍。" < / p >

# EYZ0

只在有聚集索引的表的SELECT语句中使用WITH (NOLOCK)

长一点的回答:

WITH(NOLOCK)经常被用作加速数据库读取的神奇方法。

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

如果WITH(NOLOCK)应用于具有非聚集索引的表,那么行索引可以由其他事务更改,因为行数据正在流到结果表中。这意味着结果集可能缺少行或多次显示同一行。

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

最简单的答案就是一个简单的问题——你需要你的结果是可重复的吗?如果是,那么NOLOCKS在任何情况下都不合适

如果你不需要可重复性,那么nolock可能是有用的,特别是当你不能控制所有连接到目标数据库的进程时。