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