【问题标题】:WITH(NOLOCK) : where & when to useWITH(NOLOCK) : 何时何地使用
【发布时间】:2016-03-29 18:23:54
【问题描述】:

我有 15 个被规范化以包含记录的表,并且许多用户可能在这些表中插入/更新数据(没有两个用户可以同时更新相同的记录,这受到客户端实现的限制)。这 15 个表在存储过程中一一更新。 WITH(NOLOCK) 用于选择语句以避免读锁,因为某些用户可能同时查看数据。但有时在这些过程中这些选择语句中存在锁定。根据我过去的经验,我设置了这些 nolock 以避免阻塞。

我不确定某处是否缺少 WITH(NOLOCK) 或者这是其他问题。 Should I search for missing WITH(NOLOCK)?

or what other ways are there to avoid this locking?

NOLOCK 有什么限制?我只是在读取数据,我不在乎我是否读取已提交或未提交的数据。还有什么 可以采取措施消除这种阻塞吗?

【问题讨论】:

  • 删除 NOLOCK 并使用 SET TRANSACTION ISOLATION LEVEL SNAPSHOT ?
  • 但是现在删除这些 NOLOCK 是一项艰巨的任务。它们在 SP 中无处不在。并且会比较大的变化是重新测试的条款。有没有其他办法?
  • 如果我使用 SET TRANSACTION ISOLATION LEVEL SNAPSHOT 而不更改 NOLOCK 语句。这行得通吗?
  • 您能否发布一些包含导致锁定的无锁定的查询? NoLock 与将事务级别设置为 READ UNCOMMITTED 相同。这将为整个事务设置隔离级别。也许试一试?

标签: sql sql-server tsql


【解决方案1】:

WITH(NOLOCK):

WITH (NOLOCK) 相当于使用 READ UNCOMMITED 作为事务隔离级别。

基本上它给出了脏读。即,如果任何事务持有一些数据,然后我们尝试获取数据,它将在不等待事务提交的情况下给出输出。这样我们就无需等待即可获得脏读。

因此,您将面临读取随后回滚的未提交行的风险,即从未进入数据库的数据。因此,虽然它可以防止读取被其他操作死锁,但它带来了风险。在具有高交易率的银行应用程序中,它可能不会成为您试图用它解决的任何问题的正确解决方案。

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/a3b1d05b-5479-485b-94c5-4f271adf5802/where-to-and-where-not-to-use-with-nolock?forum=transactsql

【讨论】:

    【解决方案2】:

    当您可以使用未提交的数据时,使用 WITH(NOLOCK)。

    它为您带来了巨大的性能提升,因为您的查询不会等待任何未提交的事务完成。它是一个很棒的工具,但必须小心使用,否则在您负担不起的情况下,您最终会得到未提交的数据。

    【讨论】:

      【解决方案3】:

      我认为根据您在原始帖子中留下的 cmets,您想要做的是将隔离级别设置为 READ UNCOMMITED。这与 NO LOCK 相同,只是它在整个事务上而不是在单个 select 语句上设置它。

      代码示例:

      USE DatabaseName;
      GO
      SET TRANSACTION ISOLATION LEVEL READ UNCOMMITED;
      GO
      BEGIN TRANSACTION;
      GO
      ...
      COMMIT TRANSACTION;
      GO
      

      这应该防止对数据库进行任何锁定以进行读取。然而,这也将适用于插入,这可能会出现我想象的可能的并发问题。数据在插入时可能会发生变化。

      如果您计划在此隔离级别下对数据库进行更新,我会重新考虑。

      这里是 ms sql 隔离级别的更多详细信息:https://msdn.microsoft.com/en-za/library/ms173763.aspx

      【讨论】:

        【解决方案4】:

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

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

        提示:确保表具有聚集索引的最简单方法是添加一个自动递增的 Id 主键列。

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

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

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

        在使用 INSERT、UPDATE 或 DELETE 时仍会应用锁,而这些可能是您遇到死锁的地方。

        【讨论】:

          猜你喜欢
          • 2014-02-02
          • 2011-01-14
          • 1970-01-01
          • 2012-08-20
          • 2020-04-28
          • 1970-01-01
          • 2020-10-01
          • 2019-04-22
          • 2016-03-08
          相关资源
          最近更新 更多