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