当前位置:  开发笔记 > 数据库 > 正文

什么是SQL Server中的"with(nolock)"?

如何解决《什么是SQLServer中的"with(nolock)"?》经验,为你挑选了15个好方法。

with (nolock)当你应该/不应该使用它时,有人可以解释使用查询的含义吗?

例如,如果您的银行应用程序具有较高的事务率和某些表中的大量数据,那么哪些类型的查询可以解决?是否应该经常使用它/从不使用它?



1> David M..:

WITH(NOLOCK)相当于使用READ UNCOMMITED作为事务隔离级别.因此,您将面临读取随后回滚的未提交行的风险,即从未进入数据库的数据.因此,虽然它可以防止读取被其他操作陷入僵局,但它带来了风险.在具有高交易率的银行应用程序中,对于您试图用它来解决的任何问题,它可能不会是正确的解决方案.


大多数银行应用程序可以安全地使用nolock,因为它们在商业意义上是事务性的.您只能编写新行,而不会更新它们.
@ Grauenwolf-插入但未提交的行仍然可能导致脏读.
@ Saasman-如果你没有回滚交易,那没关系.使用仅插入表,回滚的可能性很小.如果确实发生了这种情况,您仍然可以在日终差异报告中解决所有问题.
如果你使用带有`SELECT`的`NOLOCK`,那么如果在执行select时将数据插入(或更新)到表中,则存在多次返回相同行的风险(重复数据).
页面拆分怎么样?

2> Jonathan All..:

问题是更糟糕的是:

僵局,或

错误的价值?

对于财务数据库,死锁远比错误值更糟糕.我知道这听起来倒退了,但是听我说.传统的数据库事务示例是更新两行,从一行减去另一行.那是错的.

在财务数据库中,您使用业务事务.这意味着为每个帐户添加一行.完成这些事务并成功写入行至关重要.

暂时错误地获取帐户余额并不是什么大问题,这就是一天结束时的和解.并且更容易发生帐户透支,因为一次使用两台ATM而不是因为数据库未提交读取.

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

进一步阅读
行级版本控制


暂时错误地获取账户余额并不是什么大问题?如果该交易是您从atm取出现金而没有任何透支限额的交易怎么办?
@Learning:如果你在有人收到你的卡之前30秒取出钱,会发生什么?在所有沟通都不稳定之前,透支将成为生活中的事实.
迟到......应该抓住并重试死锁.脏读会产生后果
+1在金融应用程序(无处不在,不仅仅在银行),既没有更新也没有删除.通过插入记录可以纠正错误的操作.这个学期用英语怎么样?它是"storno"吗?谷歌没有帮我回答这个问题
@JonathanAllen只是一个fyi,这个词是UTmost,而不是UP.
银行经常表现出错误的平衡.根据商家系统和星期几的不同,购买可能需要几天才能实际记录到您的帐户.

3> 小智..:

不幸的是,这不只是阅读未提交的数据.在后台,您最终可能会两次阅读页面(在页面拆分的情况下),或者您可能会完全错过页面.所以你的结果可能会严重偏差.

查看Itzik Ben-Gan的文章.这是一段摘录:

"使用NOLOCK提示(或将会话的隔离级别设置为READ UNCOMMITTED),您告诉SQL Server您不期望一致性,因此无法保证.请记住,"不一致的数据"不仅意味着您可能会看到以后回滚的未提交的更改,或者事务的中间状态中的数据更改.这也意味着在扫描所有表/索引数据的简单查询中SQL Server可能会丢失扫描位置,或者您可能最终两次得到同一排."


更进一步,他解释了如何两次获取相同的行:**我将重新创建表T1,以便col1上的聚簇索引将被定义为具有选项IGNORE_DUP_KEY的唯一索引.这意味着col1中不能存在重复值,并且尝试插入重复键也不会使事务失败并生成错误而只是生成警告.**如果您不使用这个奇怪的选项,您可能不会我不得不担心两次行

4> saasman..:

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

举一个热门的例子.如果美国一家大型高街银行想要运行每小时报告,寻找银行运行的城市级别的第一个迹象,那么一个不可靠的查询可以扫描交易表,汇总每个城市的现金存款和现金提取.对于此类报告,回滚更新事务导致的错误百分比不会降低报告的值.



5> 小智..:

不确定为什么你不在数据库交易中包装金融交易(当你将资金从一个账户转移到另一个账户时 - 你不会一次性提交交易的一方 - 这就是存在明确交易的原因).即使您的代码是对业务事务进行智能处理,因为它听起来像是这样,所有事务数据库都有可能在发生错误或失败时进行隐式回滚.我认为这个讨论已经过时了.

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

没有锁不仅会返回错误的值而返回幻像记录和重复.

这是一种常见的误解,它总是使查询运行得更快.如果表上没有写锁定,则没有任何区别.如果表上有锁,它可能会使查询更快,但首先发明了锁的原因.

公平地说,这里有两个特殊场景,其中nolock提示可以提供效用

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

2)写得不好的应用程序锁定记录并将控制权返回给UI,读者被无限期阻止.如果无法修复应用程序(第三方等)并且数据库是2005之前的版本或无法启用版本控制,Nolock在这里可能会有所帮助.


当资金从不同银行的一个账户转移到另一个账户时,您认为会发生什么?一些超级数据库锁定了美国银行和富国银行的另一张桌子?不会.金融交易会写入每个金融交易,然后一个日终流程验证所有记录是否匹配.
我同意你的意见,NOLOCK不应该被用来弥补写得不好的代码.但是,我认为你对Johnathan的攻击是没有根据的,因为他从未真正提到_database_ transactions.他只是指出财务应用程序通常不允许编辑记录(显然有一些例外).在你的资金转账的例子中,他说如果你要_mutate_账户余额的价值而不是_adding_借记/贷记分录到各种分类账,这将是奇怪的.

6> Seibar..:

NOLOCK相当于READ UNCOMMITTED,但微软表示你不应该将它用于UPDATEDELETE声明:

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

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

本文适用于SQL Server 2005,因此NOLOCK如果您使用该版本,则支持存在.为了使您的代码能够面向未来(假设您决定使用脏读),您可以在存储过程中使用它:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED



7> marc_s..:

当您只读取数据时,可以使用它,而您实际上并不关心是否可能返回尚未提交的数据.

它在读取操作上可以更快,但我不能说多少.

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



8> Joel Coehoor..:

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

在一般情况下:你可以使用它时,你非常肯定它的好来读取旧数据.要记住的重要一点是它很容易弄错.例如,即使您在编写查询时没问题,您确定将来数据库中的某些内容不会发生变化,以使这些更新更加重要吗?

我也会认为它在银行应用程序中可能不是一个好主意.或库存应用.或者您在考虑交易的任何地方.


作为从事银行业务应用程序的人,我不得不说无锁不成问题.事务性记录,即插入但从未更新或删除的行,对于读取未提交数据的问题具有惊人的抵抗力.

9> dkretz..:

简单的答案 - 只要您的SQL没有改变数据,并且您的查询可能会干扰其他活动(通过锁定).

对于用于报告的任何查询,值得考虑,特别是如果查询需要超过1秒.

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

但要问的第一个问题是"为什么我担心这个?" 根据我的经验,当有人处于"尝试任何"模式时,通常会发生默认锁定行为,这是一种意外后果不太可能发生的情况.这往往是一个过早优化的情况,并且很容易被嵌入到应用程序中"以防万一".重要的是要了解你为什么这样做,它解决了什么问题,以及你是否确实遇到了问题.



10> SoftwareGeek..:

WITH (NOLOCK当你需要生成报告时,我的2美分 - 使用它是有意义的.此时,数据不会发生太大变化,您也不希望锁定这些记录.


如果您不关心当前的变化,我认为WITH(NoLOCK)会更好.

11> Andrew Hare..:

如果您正在处理财务交易,那么您永远不会想要使用nolock. nolock最好用于从具有大量更新的大型表中进行选择,并且您不关心所获得的记录是否可能已过期.

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


令人惊讶的是,在处理财务数据时,这不是问题.由于永远不会编辑行,并且在一天结束时会对帐户进行协调,因此暂时读取虚假数据不起作用.

12> Otávio Décio..:

我曾经习惯检索"下一批"的事情.在这种情况下哪个确切的项无关紧要,我有很多用户运行同一个查询.



13> Knickerless-..:

简短回答:

切勿使用WITH (NOLOCK).

答案很长:

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

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

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

这是因为其他事务正在您读取数据的同时移动数据.

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

还有其他副作用,导致牺牲你希望首先获得的速度增加.

可以说,在你可以逃脱它的地方使用它是好的,但有什么意义呢?我无法想到任何可以接受损坏数据的情况.

永远不要使用NOLOCK.

(曾经)


如果未更改最终决策,则可以接受读取未提交的数据.例如,如果你试图预测你的零售店将在未来6个月内赚多少钱,看到Tammy买了2卷纸巾,当她真的买了3卷时,不会改变你对未来的看法.
永远不要把话说绝了.如果您需要数据100%准确,那么您不应该使用nolock.对我来说,通常情况并非如此.在向用户呈现数据时,当他们对数据进行操作时,它可能已经发生了变化,但很可能没有,并且锁定争用不值得响应延迟.

14> Learning..:

使用"脏"数据时,请使用nolock.这意味着nolock还可以读取正在修改和/或未提交数据的数据.

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


您需要的唯一时间是在高交易环境中.如果你的桌子大多是空闲的,那么你就不会得到任何东西了.

15> user52212..:

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

我只能说使用提示并没有伤害我们,似乎已经使锁定问题解决了.该特定客户端的DBA基本上坚持我们使用提示.

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

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有