什么时候应该使用“with(nolock)”
有人可以解释使用with (nolock)
查询的含义,当你应该/不应该使用它?
例如,如果您的银行应用程序具有高交易率和某些表中的大量数据,那么在什么types的查询中,nolock会好起来的? 有什么情况下,你应该总是使用它/从不使用它?
WITH(NOLOCK)相当于使用READ UNCOMMITED作为事务隔离级别。 所以,你要承担阅读一个未被提交的行的风险,这个行随后会被回滚,也就是说,从来没有进入数据库的数据。 所以,虽然它可以防止读取被其他操作僵住,但是却带来了风险。 在一个高交易率的银行应用程序,它可能不会是正确的解决scheme,无论你想解决的任何问题,恕我直言。
问题是更糟糕的是:
- 一个僵局,或者
- 错误的价值?
对于金融数据库来说,死锁比错误的值要差得多。 我知道这听起来倒退,但听到我。 数据库事务的传统例子是更新两行,从一个中减去另一个。 那是错的。
在财务数据库中,您使用业务交易。 这意味着向每个帐户添加一行。 这些事务完成并且行成功写入是非常重要的。
暂时把帐户余额弄错是没有什么大不了的,那就是每天和解的目的。 而且一个账户的透支更可能发生,因为两台ATM一次被使用,而不是由于从数据库中未提交的读取。
也就是说,SQL Server 2005修复了大部分使NOLOCK
必需的bug。 所以除非你使用的是SQL Server 2000或更早版本,否则你不需要它。
进一步阅读
行级版本控制
不幸的是,这不仅仅是读取未提交的数据。 在后台,您最终可能会阅读两次页面(在页面拆分的情况下),否则您可能会错过这些页面。 所以你的结果可能会严重扭曲。
查看Itzik Ben-Gan的文章(sqlmag.com InstantDoc#92888 – http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx ):
这是一个摘录:
“使用NOLOCK提示(或将会话的隔离级别设置为READ UNCOMMITTED),您告诉SQL Server您不期望一致性,因此没有保证。请记住,”不一致的数据“不仅仅意味着您可能会看到以后回滚的未提交的更改或事务中间状态的数据更改, 也意味着在扫描所有表/索引数据的简单查询中,SQL Server可能会丢失扫描位置,或者最终可能两次获得相同的行 。“
用于合法使用nolock提示的教科书示例是针对高更新OLTP数据库的报告采样。
以一个典型的例子。 如果一家美国大型高街银行想要运行一个小时报告,寻找银行运行的城市级别的第一个迹象,那么nolock查询可以扫描每个城市的现金存款和提取现金的交易表格。 对于这样的报告,由回滚更新事务造成的极小百分比的错误不会降低报告的价值。
不知道为什么你不把数据库交易中的金融交易包装起来(例如当你将资金从一个账户转移到另一个账户时 – 你不会一次交易一个交易的一方 – 这就是明确的交易存在的原因)。 即使你的代码是商业交易的灵感来源,所有事务数据库都有可能在错误或失败的情况下进行隐式回滚。 我认为这个讨论是在你的头上。
如果您遇到locking问题,请实施版本控制并清理您的代码。
没有锁不仅返回错误的值,它返回幻影logging和重复。
这是一个常见的误解,它总是使查询运行得更快。 如果表上没有写入锁,则不会有任何区别。 如果桌子上有锁,它可能会使查询更快,但是锁首先被发明是有原因的。
公平地说,这里有两个特殊的场景,一个nolock提示可以提供效用
1)2005年以前的sql server数据库,需要运行长时间查询,对抗live OLTP数据库,这可能是唯一的方法
2)编写得不好的应用程序lockinglogging并将控制权交还给用户界面,读者无限期地被阻止。 如果应用程序无法修复(第三方等),并且数据库在2005之前版本或者版本化无法启用,Nolock在这里可能会有所帮助。
NOLOCK
相当于READ UNCOMMITTED
,但是Microsoft说你不应该把它用于UPDATE
或DELETE
语句:
对于UPDATE或DELETE语句:此function将在未来版本的Microsoft SQL Server中删除。 避免在新的开发工作中使用此function,并计划修改当前使用此function的应用程序。
http://msdn.microsoft.com/en-us/library/ms187373.aspx
本文适用于SQL Server 2005,因此如果您使用该版本,则支持NOLOCK
。 为了将来可以validation你的代码(假设你已经决定使用脏读),你可以在你的存储过程中使用它:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
另一个通常情况可以的情况是在报告数据库中,数据可能已经老化,写入不会发生。 但是,在这种情况下,pipe理员应该通过更改默认隔离级别来在数据库或表级别上设置该选项。
在一般情况下:当您确定可以读取旧数据时,可以使用它。 要记住的重要一点是很容易弄错 。 例如,即使您在编写查询的时候没问题,您确定将来数据库中的某些内容不会更改,以使这些更新更为重要吗?
我也将第二个概念,这可能不是在银行应用程序的好主意。 或库存应用程序。 或者你正在考虑交易的任何地方。
简单的答案 – 只要你的SQL不改变数据,并且你有一个查询可能会干扰其他活动(通过locking)。
值得考虑的是用于报告的任何查询,特别是如果查询花费的时间超过1秒。
如果您有针对OLTP数据库运行的OLAPtypes的报告,则此function特别有用。
然而,要问的第一个问题是“我为什么要担心这个? 根据我的经验,欺骗默认的locking行为往往发生在有人在“尝试任何”模式时,这是一个不可避免的意外后果的情况。 通常情况下,这是一个过早优化的情况,可能太容易被留在应用程序中“以防万一”。 理解你为什么要这么做是很重要的,它解决了什么问题,以及你是否真的有这个问题。
当你只读数据时,你可以使用它,而且你并不关心你是否可能获取尚未提交的数据。
它可以更快的读取操作,但我不能说多less….
一般来说,我build议不要使用它 – 读取未提交的数据可能有点混乱。
渣子
我的2美分 – 当您需要生成报告时,使用WITH (NOLOCK
)是有意义的。 在这一点上,数据不会有太大变化,你不想locking这些logging。
如果你正在处理财务交易,那么你永远不会想要使用nolock
。 nolock
最好用于从大表中select有很多更新,你不关心,如果你得到的logging可能会过时。
对于财务logging(以及大多数应用程序中的几乎所有其他logging), nolock
会造成严重破坏,因为您可能会从正在写入的logging中读取数据,而不会获取正确的数据。
我已经用来检索“下一批”的事情。 在这种情况下哪个确切的项目并不重要,而且我有很多用户运行这个相同的查询。
当你“肮脏”的数据没问题的时候使用nolock。 这意味着nolock也可以读取正在修改和/或未提交数据的过程中的数据。
在高事务环境中使用它通常不是一个好主意,这就是为什么它不是查询的默认选项。
我特别在高活动的SQLServer 2000数据库中使用(nolock)提示。 但我不确定在SQL Server 2005中是否需要它。 我最近在客户端的DBA的请求下在SQL Server 2000中添加了提示,因为他注意到很多SPIDlogging锁。
我只能说使用提示并没有伤害到我们,似乎也解决了locking问题。 那个特定客户端的DBA基本上坚持我们使用这个提示。
顺便说一句,我所处理的数据库是企业医疗索赔系统的后端,所以我们正在谈论数以百万计的logging和20多个表中的许多联合。 我通常为连接中的每个表添加WITH(nolock)提示(除非它是派生表,在这种情况下,您不能使用该特定的提示)
简短的回答:
决不
很长的回答:
NOLOCK经常被用作加速数据库读取的神奇方式,但我尽量避免使用它。
结果集可以包含尚未提交的行,这些行通常稍后会回滚。
错误或结果集可能为空,可能缺less行或多次显示相同的行。
这是因为其他交易是在您读取数据的同时移动数据。
READ COMMITTED会在单个列中多个用户同时更改同一个单元格的情况下增加了一个额外的问题。
还有其他的副作用,导致牺牲了你希望首先获得的提速。
可以说,在可以避开的地方使用它是很好的,但是有什么意义呢? 我想不出有什么情况可以接受损坏的数据。
永远不要使用NOLOCK。
(曾经)
最简单的答案是一个简单的问题 – 你需要你的结果是可重复的吗? 如果是,那么在任何情况下,NOLOCKS都是不合适的
如果你不需要重复性,那么nolocks可能是有用的,特别是如果你不能控制连接到目标数据库的所有进程。