SELECT语句中NOLOCK提示的作用


199

我想真正的问题是:

如果我不在乎脏读,将带(NOLOCK)提示添加到SELECT语句中会影响以下内容的性能:

  1. 当前的SELECT语句
  2. 给定表的其他交易

例:

Select * 
from aTable with (NOLOCK)

3
关于实际发生的情况,这些SODBA答案更为清晰。
Trisped'1

Answers:


289

1),带有的选择NOLOCK将比普通选择更快地完成。

2),带有的选择NOLOCK将允许对受影响的表进行其他查询比正常选择更快地完成。

为什么会这样呢?

NOLOCK通常(取决于您的数据库引擎)意味着将数据提供给我,并且我不在乎数据处于什么状态,并且在您读取数据时也不必费心保持数据状态。它的速度更快,资源占用更少,非常危险。

应当警告您,切勿对系统进行任何重要的更新或执行任何对系统至关重要的事情,或者在使用NOLOCK读取数据得出的绝对正确要求的情况下。绝对有可能该数据包含在查询运行期间删除的行或在尚未完成的其他会话中删除的行。此数据可能包含已部分更新的行。此数据可能包含违反外键约束的记录。此数据可能会排除已添加到表中但尚未提交的行。

您真的没有办法知道数据的状态。

如果您要获取诸如行计数或其他汇总数据之类的可接受误差范围的内容,那么这NOLOCK是提高这些查询的性能并避免对数据库性能产生负面影响的好方法。

始终NOLOCK谨慎使用提示,并处理可疑返回的任何数据。


谢谢。这是我一直以来的假设,但遭到同事的质疑,而我最初的研究使我感到怀疑。SQLServer 2005文档说NOLOCK是所有select语句的默认锁定方案!那时我想我的提示在……中是多余的
鲍勃·普罗布斯特

2
... 2005年并没有任何效果。我们现在正在运行2000(感谢供应商),并且文档中没有类似的声明。
鲍勃·普罗布斯特

4
您的朋友需要阅读文档。表提示(Transact-SQL)msdn.microsoft.com/zh-cn/library/ms187373
匹兹堡DBA

9
旁注:如果这是真的,那将是绝对的混乱。
匹兹堡DBA

1
第1点和第2点需要限制为1)“ ...,当表上有未执行插入/更新/删除操作时。” 和2)“ ...将允许对... 进行插入/更新/删除查询”。我(个人喜好)将“更快”的实例更改为“更快”的实例,因为差异正在等待另一个过程完成。
's Trisped

61

由于缺少共享锁,NOLOCK使大多数SELECT语句更快。同样,缺少锁的发行意味着您的SELECT不会妨碍编写者。

NOLOCK在功能上等效于隔离级别READ UNCOMMITTED。主要区别在于,可以选择在某些表上使用NOLOCK,但不能在其他表上使用。如果计划在复杂查询中的所有表上使用NOLOCK,则使用SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED会更容易,因为您不必将提示应用于每个表。

这是有关您可以使用的所有隔离级别的信息,以及表提示。

设置交易隔离级别

表提示(Transact-SQL)


2
我同意,但不完全同意。重要的是要指出,NO LOCK / READ UNCOMMITTED提示实际上并没有提高查询的速度,但更多的是,它使显示速度更快,因为它不必等待先前的查询完成。因此,确实,查询SEEMS更快,而不是IS更快(我认为)。
Möoz

1
@BorhanMooz好吧,不必从锁管理器请求锁可以节省很多钱。即使没有其他查询在等待,这也会带来成本和内存开销。
匹兹堡DBA

1
我正在与一些同事讨论这个问题。据我了解,使用WITH(NOLOCK)提示进行查询仍然需要获得架构共享锁(mssqltips.com/sqlservertip/2470/…)。
Möoz

1
是的,但不是页面或扩展区上的数千个共享锁。模式锁是一个锁,而不是数千个。如果我们想成为一个学究的人,我们可以继续对此争论不休,但是,是的,锁开销将很小。节省的费用可观。做一下数学计算:msdn.microsoft.com/en-us/library/aa337559(v=sql.100).aspx
匹兹堡DBA


6

它将更快,因为它不必等待锁


快多少?您能提供任何速度改进数字吗?
Eugeniu Torica

5
“多少”取决于您对数据的具体处理方式以及通常需要等待多长时间才能获取锁。
StingyJack 2010年

唯一正确的基准是您自己创建和运行的基准。每个人都告诉您的和“支票在邮件中”一样好。通过运行自己的基准测试,我已经多次证明了许多神话和假设是错误的。
TravisO 2013年

^ @TravisO-完全正确。我让NOLOCK执行得慢了几次。不确定原因,但我在故障排除时会
用到

2
  • 如果一次查询多次运行,答案是肯定的,因为每个事务都不需要等待其他事务完成。但是,如果查询单独运行一次,则答案为“否”。

  • 是的。谨慎使用WITH(NOLOCK)很有可能会整体上加快数据库的速度。这意味着其他事务不必等待此SELECT语句完成,但另一方面,其他事务将减慢速度,因为它们现在与新事务共享其处理时间。

注意WITH (NOLOCK)在具有聚集索引的表上的SELECT语句中使用。

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

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

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

READ COMMITTED(读取已提交)增加了一个额外的问题,即数据在单个列中损坏,多个用户同时更改了同一单元格。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.