了解SELECT查询的SQL Server LOCKS

Fra*_*s P 72 t-sql sql-server linq-to-sql

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

这是如何由SQL Server处理的?将一个SELECT查询块另一个SELECT查询?

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

(编辑)

关于表现:

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

mar*_*c_s 158

SELECTSQL Server中的A 将在表行上放置共享锁 - 而第二个SELECT锁也需要共享锁,并且这些锁彼此兼容.

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

什么WITH (NOLOCK)查询提示用于是能够阅读这是在被插入(由其它连接)的进程,尚未提交的数据.

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

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

还有另一个可能有用的查询提示 - WITH (READPAST).这指示SELECT命令只是跳过它尝试读取的任何行并且是唯一锁定的.该SELECT不会阻止,它将无法读取任何"脏"未提交的数据-但它可能会跳过某些行,如不显示在表中所有的行.

  • 我们在 99.5% 的选择中使用 nolock,这不是开玩笑。如果管理员正在更新用户记录,您不希望它导致报告坐在那里等待整个分布式事务完成。所以他们的旧数据显示在报告中。谁在乎?如果报告是在前一秒运行的,那将是使用 rowlock 时会出现的相同数据。唯一需要关注的地方是尚未提交的数据。如果您显示“最后一小时的订单”,这可能是一个问题,但与速度/并发性收益相比,这是一个很小的问题。 (3认同)
  • 此外,由于"报告"被抛出作为一个例子,报告通常是一段时间不是过去的5分钟.使用nolock报告上个月的数据 - 好吧,这并不是数据将在一个月后回滚. (3认同)
  • @FrancisP:如果插入少量行,则不会 - 在这种情况下,它只会锁定要插入的新行.如果一次插入超过大约5000行 - 则会发生锁定升级,并且整个表将被独占锁定. (2认同)

pap*_*zzo 32

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

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

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

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

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

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

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

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

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

  • 谢谢。我们看到类似的性能特征。如果我们需要读取锁,则我们的网站将无法运行,在大多数情况下,不使用它的影响很小。 (2认同)
  • 脏读(nolock)听起来很脏。您将永远不会获得部分数据。如果更新将John更改为Sally,那么您将永远不会获得Jolly。-我们读约翰对吗? (2认同)
  • sql服务器中的更新使用更新锁(U),该更新锁后来被转换为互斥锁(X)。(请参阅http://www.madeiradata.com/role-update-lock-sql-server/)更新锁不会阻止共享锁,但独占锁会阻止所有其他锁(请参阅https://msdn.microsoft.com /en-us/library/ms186396(v=sql.105).aspx)。 (2认同)

Dan*_*vey 8

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

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

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

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

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

  • 事务不会相互阻塞 - 选择将阻止更新.这里有几个有趣的链接,帮助我更多地了解这些东西是如何工作的:[第一个](http://blog.sqlauthority.com/2012/11/15/sql-server-concurrency-basics- guest-post-by-vinod-kumar /)[second one](http://blogs.extremeexperts.com/2012/11/15/sql-server-locking-basics/) (2认同)

Mil*_*jka 7

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

检查另一个线程

/sf/answers/382846691/

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

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