首页 文章

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

提问于
浏览
543

当你应该/不应该使用它时,有人可以解释使用 with (nolock) 对查询的影响吗?

例如,如果您的银行应用程序具有较高的事务率和某些表中的大量数据,那么哪些类型的查询可以解决?是否应该经常使用它/从不使用它?

16 回答

  • 157

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

  • 4

    问题是更糟糕的是:

    • 死锁,或者

    • 错误的值?

    对于财务数据库,死锁远比错误值更糟糕 . 我知道这听起来倒退了,但是听我说 . 传统的数据库事务示例是更新两行,从一行减去另一行 . 那是错的 .

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

    暂时错误地获取帐户余额并不是什么大问题,这就是一天结束时的和解 . 并且更容易发生帐户透支,因为一次使用两台ATM而不是因为数据库未提交读取 .

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

    Further Reading
    Row-Level Versioning

  • 9

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

    举一个热门的例子 . 如果美国一家大型高街银行想要运行每小时报告,寻找银行运行的城市级别的第一个迹象,那么一个不可靠的查询可以扫描交易表,汇总每个城市的现金存款和现金提取 . 对于此类报告,回滚更新事务导致的错误百分比不会降低报告的值 .

  • 6

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

    看看Itzik Ben-Gan's article . 这是一段摘录:

    “使用NOLOCK提示(或将会话的隔离级别设置为READ UNCOMMITTED),您告诉SQL Server您不期望一致性,因此无法保证 . 请记住,”不一致的数据“不仅意味着您可能会看到以后回滚的未提交更改,或者事务的中间状态中的数据更改 . 这也意味着在扫描所有表/索引数据的简单查询中SQL Server可能会丢失扫描位置,或者您可能会结束两次同一排 . “

  • 30

    不确定为什么你不在数据库交易中包装金融交易(当你将资金从一个账户转移到另一个账户时 - 你不会一次性提交交易的一方 - 这就是存在明确交易的原因) . 即使您的代码是对业务事务进行智能处理,因为它听起来像是这样,所有事务数据库都有可能在发生错误或失败时进行隐式回滚 . 我认为这个讨论已经过时了 .

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

    没有锁不仅会返回错误的值,而且还会返回幻像记录和重复项 .

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

    公平地说,这里有两个特殊场景,其中nolock提示可以提供效用

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

    2)写得不好的应用程序锁定记录并将控制权返回给UI,读者被无限期阻止 . 如果应用程序无法修复(第三方等),数据库也是如此,Nolock在这里可能会有所帮助2005年之前或版本控制无法打开 .

  • 17

    NOLOCK 相当于 READ UNCOMMITTED ,但是Microsoft说你不应该将它用于 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

  • 16

    当您只读取数据时,可以使用它,而您实际上并不关心是否可能返回尚未提交的数据 .

    它在读取操作上可以更快,但我不能说多少 .

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

  • 13

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

    在一般情况下:当您确定可以读取旧数据时,可以使用它 . 要记住的重要一点是它很容易弄错 . 例如,即使将来在数据库中进行更改以使这些更新更加重要?

    我在银行应用程序中可能不是一个好主意 . 或库存应用 . 或者您在考虑交易的任何地方 .

  • 8

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

    对于用于报告的任何查询,值得考虑,特别是如果查询需要超过1秒 .

    如果您正在针对OLTP数据库运行OLAP类型的报告,那么它尤其有用 .

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

  • 23

    我的2美分 - 当你需要生成报告时使用 WITH (NOLOCK 是有意义的 . 此时,数据不会想要锁定那些记录 .

  • 49

    如果您正在处理财务交易,那么您永远不会想要使用 nolock . nolock 最适合从具有大量更新的大型表中进行选择,并且您不关心您获得的记录是否可能已过期 .

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

  • 7

    我曾经习惯检索“下一批”的事情 . 在这种情况下哪个确切的项无关紧要,我有很多用户运行同一个查询 .

  • 6

    使用“脏”数据时,请使用nolock . 这意味着nolock还可以读取正在修改和/或未提交数据的数据 .

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

  • 3

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

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

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

  • 50

    Short answer:

    永远不要使用 WITH (NOLOCK) .

    Long answer:

    NOLOCK经常被利用作为加速数据库读取的神奇方法,但我尽量避免使用它 .

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

    错误或结果集可以为空,缺少行或多次显示同一行 .

    这是因为其他事务正在您读取数据的同时移动数据 .

    READ COMMITTED添加了一个额外的问题,其中数据在单个列中被破坏,其中多个用户同时更改同一个单元 .

    还有其他副作用,导致牺牲你希望首先获得的速度增加 .

    可以说,在你可以逃脱它的地方使用它是好的,但有什么意义呢?我无法想到任何可以接受损坏数据的情况 .

    永远不要使用NOLOCK .

    (曾经)

  • 399

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

    如果您不需要可重复性,则nolocks可能很有用,尤其是如果您无法控制连接到目标数据库的所有进程 .

相关问题