89

我想知道SELECT WITH (NOLOCK)如果影响该表的唯一其他查询是SELECT查询,那么在表上使用有什么好处。

SQL Server 是如何处理的?一个SELECT查询会阻塞另一个SELECT查询吗?

我正在使用 SQL Server 2012 和 Linq-to-SQL DataContext

(编辑)

关于性能:

  • 如果使用lock ,第二个SELECT是否必须等待第一个SELECT完成SELECT
  • SELECT WITH (NOLOCK)?
4

6 回答 6

198

SELECTSQL Server 中的 A将在表行上放置一个共享锁SELECT- 第二个也需要一个共享锁,并且它们彼此兼容。

所以没有人SELECT不能阻止另一个人SELECT

查询提示的WITH (NOLOCK)用途是能够读取正在插入(通过另一个连接)并且尚未提交的数据。

如果没有该查询提示,aSELECT可能会被正在进行的INSERT(或UPDATE)语句阻止读取表,该语句将排他锁放置在行(或可能是整个表)上,直到该操作的事务已提交(或回滚)。

提示的问题WITH (NOLOCK)是:您最终可能正在读取根本不会插入的数据行(如果INSERT事务回滚) - 因此您的例如报告可能会显示从未真正提交到数据库的数据.

还有另一个可能有用的查询提示 - WITH (READPAST)。这指示该SELECT命令仅跳过它尝试读取且被独占锁定的任何行。SELECT不会阻塞,也不会读取任何“脏”未提交的数据——但它可能会跳过一些行,例如不显示表中的所有行。

于 2012-09-26T21:02:12.873 回答
35

在性能方面,您始终专注于选择。
Shared 不会阻止读取。
共享锁块更新。
如果您有数百个共享锁,则更新需要一段时间才能获得独占锁,因为它必须等待共享锁清除。

默认情况下,选择(读取)采用共享锁。
共享 (S) 锁允许并发事务读取 (SELECT) 资源。
共享锁对其他选择(1 或 1000)没有影响。

区别在于 nolock 与 shared lock 效果如何更新或插入操作。

当资源上存在共享 (S) 锁时,没有其他事务可以修改数据。

共享锁会阻止更新!
但是 nolock 不会阻止更新。

这会对更新的性能产生巨大影响。它也会影响刀片。

脏读(nolock)听起来很脏。你永远不会得到部分数据。如果更新将 John 更改为 Sally,您将永远无法获得 Jolly。

我经常使用共享锁来实现并发性。数据一读就过时了。下一毫秒更改为 Sally 的 John 的读取是陈旧数据。在下一毫秒回滚 John 的 Sally 读取是陈旧数据。那是在毫秒级别。如果用户使用共享锁,我有一个数据加载器需要 20 小时才能运行,而如果用户没有使用锁,则需要 4 小时才能运行。在这种情况下,共享锁会导致数据过期 16 小时。

不要错误地使用 nolocks。但他们确实有一席之地。如果您要在一个字节设置为 1 时取消检查,然后在检查被取消时将其设置为 2 - 不是不锁定的时间。

于 2012-09-26T22:31:46.157 回答
14

我必须添加一条重要的评论。每个人都在提到NOLOCK只读取脏数据。这并不精确。您也可能会两次获得同一行,或者在阅读期间跳过整行。原因是当 SQL Server 重新平衡 b-tree 时,您可能会同时请求一些数据。

检查其他线程

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx )

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

于 2015-03-04T08:59:52.990 回答
10

在我的工作中,我们有一个非常大的系统,它同时在多台 PC 上运行,有非常大的表,有数十万行,有时甚至数百万行。

当你在一个非常大的表上做一个 SELECT 时,假设你想知道一个用户在过去 10 年中所做的每一笔交易,并且表的主键没有以有效的方式构建,查询可能需要几分钟跑步。

然后,我们的应用程序可能同时在许多用户的 PC 上运行,访问同一个数据库。因此,如果有人试图插入另一个 SELECT 正在读取的表中(在 SQL 试图读取的页面中),则可能会发生 LOCK 并且两个事务相互阻塞。

我们必须在我们的 SELECT 语句中添加一个“NO LOCK”,因为它是一个巨大的 SELECT 表,同时被很多用户大量使用,而且我们一直都有 LOCKS。

不知道我的例子够不够清楚?这是一个现实生活中的例子。

于 2012-09-26T19:34:02.033 回答
3

允许读取未提交的SELECT WITH (NOLOCK)数据,这相当于READ UNCOMMITTED在您的数据库上设置了隔离级别。与在整个数据库上设置隔离级别相比,NOLOCK关键字允许更细粒度的控制。

维基百科有一篇有用的文章:维基百科:隔离(数据库系统)

它还在其他 stackoverflow 文章中详细讨论。

于 2014-12-05T08:42:29.327 回答
1

select with no lock - 将选择可能/可能不会插入的记录。您将读取脏数据。

例如 - 假设一个事务插入 1000 行然后失败。

当您选择时 - 您将获得 1000 行。

于 2012-09-26T19:15:23.193 回答