有人可以解释使用with (nolock)
查询的含义,什么时候应该/不应该使用它?
例如,如果您的银行应用程序具有高交易率并且某些表中有大量数据,那么在哪些类型的查询中可以使用 nolock?是否存在您应该始终使用它/从不使用它的情况?
有人可以解释使用with (nolock)
查询的含义,什么时候应该/不应该使用它?
例如,如果您的银行应用程序具有高交易率并且某些表中有大量数据,那么在哪些类型的查询中可以使用 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 查询可以扫描交易表,汇总每个城市的现金存款和现金取款。对于这样的报告,由回滚更新事务引起的错误的微小百分比不会降低报告的价值。
不知道为什么您不将金融交易包装在数据库交易中(例如当您将资金从一个帐户转移到另一个帐户时 - 您不会一次提交交易的一侧 - 这就是存在显式交易的原因)。即使您的代码听起来像是对业务事务脑死亡,但所有事务数据库都有可能在发生错误或失败时进行隐式回滚。我认为这个讨论超出了你的想象。
如果您遇到锁定问题,请实施版本控制并清理您的代码。
无锁不仅会返回错误的值,还会返回幻像记录和重复项。
一个常见的误解是它总是使查询运行得更快。如果表上没有写锁,则没有任何区别。如果表上有锁,它可能会使查询更快,但首先发明锁是有原因的。
公平地说,这里有两种特殊情况,其中 nolock 提示可以提供实用程序
1) 需要对实时 OLTP 数据库运行长查询的 2005 年之前的 sql server 数据库,这可能是唯一的方法
2) 写得很糟糕的应用程序会锁定记录并将控制权返回给 UI,并且阅读器会被无限期地阻塞。如果无法修复应用程序(第三方等)并且数据库是 2005 之前的版本或无法打开版本控制,则 Nolock 在这里会很有帮助。
NOLOCK
等同于READ UNCOMMITTED
,但微软表示您不应将其用于UPDATE
orDELETE
语句:
对于 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)
在具有聚集索引的表上的 SELECT 语句中使用。
长答案:
WITH(NOLOCK) 通常被用作加快数据库读取速度的神奇方法。
结果集可以包含尚未提交的行,这些行通常稍后会回滚。
如果将 WITH(NOLOCK) 应用于具有非聚集索引的表,则当行数据流式传输到结果表时,其他事务可以更改行索引。这意味着结果集可能会丢失行或多次显示同一行。
READ COMMITTED 增加了一个额外的问题,即多个用户同时更改同一单元格的单个列中的数据损坏。
WITH (NOLOCK
我的 2 美分 -当您需要生成报告时使用 ) 是有意义的。在这一点上,数据不会有太大变化并且您不想锁定这些记录。
如果您正在处理金融交易,那么您将永远不想使用nolock
. nolock
最好用于从具有大量更新的大型表中进行选择,并且您不在乎您获得的记录是否可能已过时。
对于财务记录(以及大多数应用程序中的几乎所有其他记录)nolock
会造成严重破坏,因为您可能会从正在写入的记录中读取数据而无法获得正确的数据。
我曾经为要做的事情检索“下一批”。在这种情况下,确切的项目并不重要,我有很多用户运行相同的查询。
当您对“脏”数据没问题时,请使用 nolock。这意味着 nolock 也可以读取正在修改和/或未提交数据的过程中的数据。
在高事务环境中使用它通常不是一个好主意,这就是为什么它不是查询的默认选项。
我使用 with (nolock) 提示,特别是在具有高活动性的 SQLServer 2000 数据库中。但是,我不确定 SQL Server 2005 是否需要它。我最近应客户 DBA 的请求在 SQL Server 2000 中添加了该提示,因为他注意到了很多 SPID 记录锁。
我只能说,使用提示并没有伤害到我们,而且似乎已经解决了锁定问题。该特定客户的 DBA 基本上坚持我们使用提示。
顺便说一句,我处理的数据库是企业医疗索赔系统的后端,所以我们谈论的是数百万条记录和 20 多个表在许多连接中。我通常为连接中的每个表添加 WITH (nolock) 提示(除非它是派生表,在这种情况下您不能使用该特定提示)
最简单的答案是一个简单的问题——你需要你的结果是可重复的吗?如果是,那么 NOLOCKS 在任何情况下都不合适
如果您不需要可重复性,那么 nolocks 可能很有用,特别是如果您无法控制连接到目标数据库的所有进程。