【问题标题】:Select with (nolock)使用 (nolock) 选择
【发布时间】:2014-05-05 07:40:50
【问题描述】:

我的老板一直强迫我用with (nolock) 编写SELECT 查询以防止死锁。但是 AFAIK,默认情况下 Select 语句没有锁,因此使用 with (nolock) 选择和不选择没有任何区别。如果我错了,请纠正我。

两个查询:

SELECT * from EMP with (nolock)

SELECT * from EMP 

两者不一样。如果我不放 nolock 会不会容易出现死锁?请告诉我应该使用什么。

【问题讨论】:

  • 视情况而定。在高插入情况下,使用 with(nolock) 可能会读取不正确的数据(不仅仅是陈旧的数据)。 brentozar.com/archive/2011/11/… 修复实际问题,而不是症状。如果您所做的只是在 SSMS 中运行太宽(选择 *)、太大(没有 WHERE 子句)查询以检查数据(如上面的示例),那么是的,使用 with(nolock)
  • 这是另一个关于这个主题的好问题stackoverflow.com/questions/1452996/…
  • 说 SELECT 查询不做任何锁定是不正确的,在默认事务隔离级别下,即 READ COMMITTED 选择查询确实获得资源上的共享锁。当使用 NOLOCK 查询提示时,它根本不需要任何锁。正如米奇在没有获得锁时提到的那样,您的查询对脏读(未提交的数据)是开放的。
  • 我推荐阅读这篇关于sql server中锁和死锁的文章aboutsqlserver.com/lockingblocking

标签: sql-server sql-server-2008 select deadlock


【解决方案1】:

使用 Nolocks 时应格外小心。对nolock(read uncommitted)hint最常见的理解是它读取了尚未提交的数据。但是,还有其他可能非常危险的副作用。 (搜索“nolock”和“page splits”)

这里写得真好...http://sqlmag.com/sql-server/beware-nolock-hint

简而言之,“不锁定”一切并不总是一个好主意……如果有的话。

【讨论】:

    【解决方案2】:

    假设我们有默认的事务隔离级别 READ COMMITTED ,即使在非常简单的 SELECT 语句中也有可能出现死锁,想象一下 User1 只读取数据而 User2 尝试更新一些数据并且没有该表上的聚集索引,这是可能的。

    1. User1 正在读取一些数据并在非聚集索引上获取共享锁以执行查找,然后尝试在包含数据的页面上获取共享锁以返回数据本身.

    2. 正在写入/更新的用户2首先在包含数据的数据库页面上获得排他锁,然后尝试在索引上获得排他锁以更新索引。

    【讨论】:

      【解决方案3】:

      SELECT 语句确实会应用锁,除非查询顶部有语句 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED。

      无论如何,在具有聚集索引的表上的 SELECT 语句中使用WITH (NOLOCK),但只有在需要时才这样做会更明智。

      提示:向表中添加聚集索引的最简单方法是添加 Id 主键列。

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

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

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

      牢记 WITH(NOLOCK) 导致的问题将帮助您调整数据库。

      至于你的老板,把他们当成一个挑战。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-15
        • 1970-01-01
        • 2014-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-22
        • 1970-01-01
        相关资源
        最近更新 更多