【问题标题】:Effect of NOLOCK hint in SELECT statementsSELECT 语句中 NOLOCK 提示的效果
【发布时间】:2010-09-17 15:11:20
【问题描述】:

我想真正的问题是:

如果我不关心脏读,在 SELECT 语句中添加 with (NOLOCK) 提示会影响:

  1. 当前的 SELECT 语句
  2. 针对给定表的其他事务

例子:

Select * 
from aTable with (NOLOCK)

【问题讨论】:

  • 这些SODBA 的答案对于实际发生的事情更加清晰。

标签: sql sql-server locking


【解决方案1】:
  • 如果查询一次运行多次,答案是,因为每个事务不需要等待其他事务完成。但是,如果查询单独运行一次,则答案是否定的。

  • 是的。仔细使用 WITH(NOLOCK) 很有可能会整体加快数据库速度。这意味着其他事务不必等待此 SELECT 语句完成,但另一方面,其他事务将减慢速度,因为它们现在与新事务共享其处理时间。

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

WITH(NOLOCK) 通常被用作加速数据库读取事务的神奇方式。

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

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

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

【讨论】:

    【解决方案2】:

    1) 是的,带有NOLOCK 的选择将比普通选择更快地完成。

    2) 是的,带有NOLOCK 的选择将允许针对受影响表的其他查询比正常选择更快地完成。

    为什么会这样?

    NOLOCK 通常(取决于您的数据库引擎)意味着给我您的数据,我不在乎它处于什么状态,并且在您读取它时不要打扰它。它同时速度更快,资源消耗更少,而且非常非常危险。

    您应该被警告永远不要更新或执行任何系统关键操作,或者使用源自NOLOCK 读取的数据需要绝对正确性的地方。此数据绝对有可能包含在查询运行期间已删除的行或在尚未完成的其他会话中已删除的行。此数据可能包含已部分更新的行。此数据可能包含违反外键约束的记录。此数据可能会排除已添加到表中但尚未提交的行。

    你真的无法知道数据的状态是什么。

    如果您尝试获取诸如行计数或其他可以接受一些误差范围的汇总数据,那么NOLOCK 是提高这些查询的性能并避免它们对数据库性能产生负面影响的好方法。

    始终谨慎使用NOLOCK 提示,并对它返回的任何可疑数据进行处理。

    【讨论】:

    • 谢谢。这是我一直假设的,但被一位同事质疑,我最初的研究让我质疑自己。 SQLServer 2005 文档说 NOLOCK 是所有选择语句的默认锁定方案!我猜我的提示在...中会是多余的
    • ... 2005 并且没有任何效果。我们现在正在运行 2000(感谢我们的供应商),文档中没有类似的声明。
    • 您的朋友需要阅读文档。表提示 (Transact-SQL) msdn.microsoft.com/en-us/library/ms187373(SQL.90).aspx
    • 旁注:如果这是真的,那将是绝对的混乱。
    • 第 1 点和第 2 点需要限制为 1)“...当插入/更新/删除操作在表上挂起时。”和 2) “... 将允许 insert/update/delete 查询 ...”。我会(个人偏好)将“更快”的实例更改为“更快”,因为不同之处在于等待另一个过程完成。
    【解决方案3】:

    除了上面所说的之外,您应该非常清楚 nolock 实际上会给您带来获取在选择之前提交的行的风险。

    http://blogs.msdn.com/sqlcat/archive/2007/02/01/previously-committed-rows-might-be-missed-if-nolock-hint-is-used.aspx

    【讨论】:

      【解决方案4】:

      NOLOCK 使大多数 SELECT 语句更快,因为缺少共享锁。此外,没有发布锁意味着写入器不会受到您的 SELECT 的阻碍。

      NOLOCK 在功能上等同于 READ UNCOMMITTED 隔离级别。主要区别在于,如果您愿意,您可以在某些表上使用 NOLOCK,但不能在其他表上使用。如果您计划对复杂查询中的所有表使用 NOLOCK,那么使用 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 会更容易,因为您不必将提示应用于每个表。

      这里是有关您可以使用的所有隔离级别的信息,以及表格提示。

      SET TRANSACTION ISOLATION LEVEL

      Table Hint (Transact-SQL)

      【讨论】:

      • 我同意,但不完全同意;重要的是要指出,NO LOCK / READ UNCOMMITTED 提示实际上并没有提高查询的速度,但更多的是使它看起来更快,因为它不必等待先前的查询完成。所以真的,查询看起来更快,而不是更快(我认为)。
      • @BorhanMooz 好吧,不必向锁管理器请求锁可以节省开支。即使没有其他查询在等待,这也有成本和内存开销。
      • 我正在和我的一些同事讨论这个问题。据我了解,使用 WITH(NOLOCK) 提示的查询仍然需要获得模式共享锁 (mssqltips.com/sqlservertip/2470/…)。
      • 是的,但不是页面或范围上的数千个共享锁。架构锁是一个锁,而不是数千个。如果我们想学究气,我们可以继续讨论这个问题,但是是的,锁开销是最小的。节省的费用非常可观。算一算:msdn.microsoft.com/en-us/library/aa337559(v=sql.100).aspx
      【解决方案5】:

      它会更快,因为它不必等待锁

      【讨论】:

      • 快多少?你能提供任何速度改进的数字吗?
      • “多少”取决于您具体如何处理数据以及您通常需要等待多长时间才能获得锁。
      • 唯一正确的基准是您自己创建和运行的基准。每个人都告诉你的就像“支票在邮件里”一样好。通过运行我自己的基准测试,我多次证明了许多神话和假设是错误的。
      • ^ @TravisO - 完全正确。我已经让 NOLOCK 执行慢了几次。不完全确定原因,但我在故障排除时使用它,我不想对生产产生负面(过度)影响
      猜你喜欢
      • 2011-05-03
      • 2011-04-22
      • 1970-01-01
      • 1970-01-01
      • 2016-11-21
      • 1970-01-01
      • 1970-01-01
      • 2013-10-18
      相关资源
      最近更新 更多