了解SELECT查询的SQL Server LOCKS

时间:2012-09-26 19:12:30

标签: sql-server tsql linq-to-sql

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

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

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

(编辑)

关于表现:

  • 如果使用锁定的SELECT,第二个SELECT是否必须等待第一个SELECT完成?
  • SELECT WITH (NOLOCK)
  • 对比

6 个答案:

答案 0 :(得分:147)

SQL Server中的SELECT会在表行上放置共享锁 - 而第二个SELECT也需要共享锁,并且这些锁是一个另一个。

所以没有 - 一个SELECT无法阻止另一个SELECT

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

如果没有该查询提示,可能会阻止SELECT正在通过正在发送独占锁定的INSERT(或UPDATE)语句读取表格行(或可能是整个表),直到该操作的事务已提交(或回滚)。

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

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

答案 1 :(得分:31)

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

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

区别在于nolock与共享锁定效果如何更新或插入操作。

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

共享锁阻止更新!
但是nolock并没有阻止更新。

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

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

我使用共享锁来实现并发。一旦读取数据,数据就会过时。阅读约翰,读到下一毫秒的莎莉是陈旧的数据。阅读Sally,在下一毫秒内回滚John是陈旧的数据。那是在毫秒级别。我有一个数据加载器,如果用户正在使用共享锁,需要20个小时才能运行,运行4个小时就是用户无法锁定。在这种情况下,共享锁会导致数据过时16小时。

不要使用错误的nolocks。但他们确实有一席之地。如果要在字节设置为1时剪切检查,然后在剪切检查时将其设置为2,而不是nolock的时间。

答案 2 :(得分:8)

在我的工作中,我们有一个非常庞大的系统,可以在许多PC上同时运行,非常大的表包含数十万行,有时还有数百万行。

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

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

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

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

答案 3 :(得分:7)

我必须添加一条重要评论。每个人都提到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可能会丢失扫描位置,或者您最终可能会获得相同的行两次。

答案 4 :(得分:2)

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

维基百科有一篇有用的文章:Wikipedia: Isolation (database systems)

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

答案 5 :(得分:1)

选择没有锁定 - 将选择可能/可能不会插入的记录。你会读到一个脏数据。

例如

- 假设事务插入1000行然后失败。

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