SQL Server 中的“with (nolock)”是啥?

Posted

技术标签:

【中文标题】SQL Server 中的“with (nolock)”是啥?【英文标题】:What is "with (nolock)" in SQL Server?SQL Server 中的“with (nolock)”是什么? 【发布时间】:2009-03-26 17:13:35 【问题描述】:

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

例如,如果您的银行应用程序具有高交易率并且某些表中有大量数据,那么在哪些类型的查询中可以使用 nolock?是否存在应该始终使用/从不使用它的情况?

【问题讨论】:

我在***.com/questions/3836282/… 和***.com/questions/3836032/… 中进行了子提问,主要是乔纳森艾伦的回答***.com/questions/686724/… 这里有一个链接 - mssqltips.com/sqlservertip/2470/… 这里是对使用 NOLOCK blogs.msdn.com/b/davidlean/archive/2009/04/06/…的影响的一个很好的总结 【参考方案1】:

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

【讨论】:

大多数银行应用程序可以安全地使用 nolock,因为它们在商业意义上是事务性的。你只写新行,你从不更新它们。 @Grauenwolf- 插入但未提交的行仍可能导致脏读。 @Saasman- 如果您从不回滚事务,那没关系。并且对于仅插入表,回滚的可能性微乎其微。如果它们确实发生了,您仍将在日终差异报告中解决所有问题。 如果您将NOLOCKSELECT 一起使用,如果在执行操作时曾经将数据插入(或更新)到表中,则可能会多次返回相同的行(重复数据)选择。 这是值得明确说的:如果您需要准确、可重复的查询结果,则不应使用 NOLOCK。时期。关于它们可以安全地用于银行应用程序的主要断言是不准确的。如果您可以容忍一些保真度的损失,那么只有这样使用才合适。【参考方案2】:

问题是什么更糟:

死锁,或 值错误?

对于金融数据库,死锁比错误值更糟糕。我知道这听起来倒退了,但请听我说完。数据库事务的传统示例是更新两行,从其中减去并添加到另一行。这是错误的。

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

暂时弄错帐户余额没什么大不了的,这就是日终对账的目的。与未提交的数据库读取相比,同时使用两台 ATM 导致帐户透支的可能性要大得多。

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

进一步阅读Row-Level Versioning

【讨论】:

账户余额暂时出错不是什么大事吗?如果该交易是您从自动取款机中取出现金而没有任何透支限制的交易怎么办? @Learning:如果您在有人向您的卡收费前 30 秒取出钱会怎样?直到所有的沟通都变得即时,透支将成为生活中的事实。 +1 在金融应用程序中(无处不在,不仅在银行中),既没有更新也没有删除。甚至不正确的操作也可以通过插入记录来纠正。这个英文术语是什么?是“斯托诺”吗?谷歌没有帮我回答这个问题 延迟进入...应该捕获并重试死锁。脏读会产生后果 @JonathanAllen 仅供参考,这个词是 UTmost,而不是 UP。【参考方案3】:

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

查看Itzik Ben-Gan's article。摘录如下:

" 带有 NOLOCK 提示(或设置 要读取的会话的隔离级别 未提交)你告诉 SQL Server 你不期望一致性,所以有 没有保证。但请记住 “不一致的数据”不仅 意味着您可能会看到未提交 后来回滚的更改, 或中间的数据变化 交易的状态。 这也是 意味着在一个简单的查询中 扫描所有表/索引数据 SQL Server 可能会丢失扫描位置,或者您 可能最终得到同一行 两次。 "

【讨论】:

再往下一点,他解释了如何两次获取同一行:我将重新创建表 T1,这样 col1 上的聚集索引将被定义为带有选项 IGNORE_DUP_KEY 的唯一索引.这意味着 col1 中不能存在重复值,并且尝试插入重复键不会使事务失败并生成错误,而只会生成警告。 如果您不使用这个奇怪的选项,您可能不必担心获得两次行 即使没有连线选项,您仍然可以获得重复行 - 例如,如果您的查询利用非唯一索引。不过,这并不是 nolock 独有的。【参考方案4】:

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

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

【讨论】:

【参考方案5】:

不确定您为什么不将金融交易包装在数据库交易中(例如当您将资金从一个账户转移到另一个账户时 - 您不会一次提交交易的一侧 - 这就是存在显式交易的原因) .即使您的代码听起来像是对业务事务脑死亡,但所有事务数据库都有可能在发生错误或失败时进行隐式回滚。我认为这个讨论超出了你的想象。

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

无锁不仅会返回错误的值,还会返回幻像记录和重复项。

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

公平地说,这里有两种特殊情况,其中 nolock 提示可以提供实用性

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

2) 编写不佳的应用程序会锁定记录并将控制权返回给 UI,并且读取器会被无限期地阻塞。如果应用程序无法修复(第三方等)并且数据库是 2005 之前的版本或无法打开版本控制,则 Nolock 在这里会很有帮助。

【讨论】:

我同意你的观点,NOLOCK 不应该用来弥补写得不好的代码。但是,我认为您对 Johnathan 的攻击是没有根据的,因为他实际上从未提及 database 事务。他只是指出财务应用程序通常不允许编辑记录(显然有一些例外)。在您的资金转移示例中,他说如果您要改变帐户余额的值而不是添加借方/贷方条目到各种分类帐中,那将是很奇怪的. 当资金从一个账户转移到不同银行的另一个账户时,您认为会发生什么?一些超级数据库锁定了美国银行的一张桌子和富国银行的另一张桌子?不会。金融交易会写入每个人,然后一个日终流程会验证所有记录是否匹配。【参考方案6】:

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】:

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

读取操作可能会更快,但我不能真正说出多少。

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

【讨论】:

如果您提到 SQL Server 2005 具有行版本控制,因此甚至不再需要 nolocks,那就太好了。 好吧,即使在 SQL Server 2005 中,“with (nolock)”仍然占有一席之地 - 但好处越来越小,这是真的。【参考方案8】:

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

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

我也会第二个观点,即在银行应用程序中这可能不是一个好主意。或库存应用程序。或任何您考虑交易的地方。

【讨论】:

作为一个从事银行应用程序的人,我不得不说无锁不是问题。事务性记录(即插入但从未更新或删除的行)对读取未提交数据的问题具有惊人的抵抗力。【参考方案9】:

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

对于用于报告的任何查询都值得考虑,尤其是在查询时间超过 1 秒时。

如果您有针对 OLTP 数据库运行的 OLAP 类型的报告,这将特别有用。

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

【讨论】:

【参考方案10】:

简答:

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

长答案:

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

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

如果将 WITH(NOLOCK) 应用于具有非聚集索引的表,则当行数据流式传输到结果表时,其他事务可以更改行索引。这意味着结果集可能会丢失行或多次显示同一行。

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

【讨论】:

如果不改变最终决定,读取未提交的数据是可以接受的。例如,如果你想预测你的零售店在接下来的 6 个月里会赚多少钱,看到 Tammy 买了 2 卷纸巾,而她真的买了 3 卷,这不会改变你对未来的看法. 如果您的过滤器现在包括,您的数据将在您运行查询时不准确。如果您的过滤器仅包含历史数据,则使用 READ UNCOMITTED 根本不会影响它。它被包含在 ANSI 标准中是有原因的。 永远不要说永远。如果您需要 100% 准确的数据,那么您不应该使用 nolock。对我来说,通常情况并非如此。当向用户展示数据时,当他们对数据采取行动时,它可能已经发生了变化,但很可能没有发生变化,而且锁争用不值得响应延迟。 让我们坚持值得存在的系统。不要忘记 Tammy 的大脑非常好,因此使用数据库记录没有人注意到的微小纸巾购买充其量是荒谬的。我们的重点是实际上很重要的系统,例如。让人们按时付款,响应紧急情况等。 对任何值得存在的系统进行编程的人都理解 WITH(NOLOCK) 的使用是非常有益的。当一个人可以比数据库做得更好时,请考虑重新利用这些资源。【参考方案11】:

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

【讨论】:

如果你不关心当前的变化,我认为 WITH (NoLOCK) 更好。【参考方案12】:

如果您正在处理金融交易,那么您将永远不想使用nolocknolock 最好用于从具有大量更新的大型表中进行选择,并且您不在乎您获得的记录是否可能已过期。

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

【讨论】:

令人惊讶的是,在处理财务数据时,这不是问题。由于从不编辑行并且在一天结束时对帐户进行核对,因此暂时读取虚假数据无济于事。【参考方案13】:

我习惯于检索“下一批”来做事。在这种情况下,确切的项目并不重要,我有很多用户运行相同的查询。

【讨论】:

我们做一些类似的事情来呈现一个后台任务,并有一系列工作要做。如果,当它到达特定记录时,它不再存在/不匹配选择标准,它只会移动到下一个。【参考方案14】:

当您对“脏”数据没问题时,请使用 nolock。这意味着 nolock 也可以读取正在修改和/或未提交数据的过程中的数据。

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

【讨论】:

您唯一需要它的时候是在高交易环境中。如果您的桌子大部分时间都是闲置的,那么您将不会从中获得任何收益。【参考方案15】:

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

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

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

【讨论】:

SQL Server 2005 添加了“行版本控制”,这将大大减少对 nolocks 的需求。我们最近升级了,并且没有培训我们的 DBA 停止使用它们。【参考方案16】:

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

如果您不需要可重复性,那么 nolocks 可能很有用,特别是如果您无法控制连接到目标数据库的所有进程。

【讨论】:

以上是关于SQL Server 中的“with (nolock)”是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用sql server数据库中的标量值函数

sql SQL SERVER中的组连接

sql SQL Server中的常量

sqlserver之[SQL Server]缓冲池中的可用内存不足。[Microsoft][ODBC SQL Server Driver][SQL Server]语句已终止

在sql server2008中的日期类型是啥

如何查看sql server 2008的SQL语句执行错误日志