我在MSDN上阅读一些文档,其中提到“不会发出共享锁来防止其他事务修改当前事务读取的数据”。
换言之,这会导致脏读问题。这太危险了,那么为什么还要使用它呢?
有人知道实际应用场景吗?
我在MSDN上阅读一些文档,其中提到“不会发出共享锁来防止其他事务修改当前事务读取的数据”。
换言之,这会导致脏读问题。这太危险了,那么为什么还要使用它呢?
有人知道实际应用场景吗?
在我们之前的工作中,我们使用这个方法来获取大致数字。例如,如果有一张表格记录了一天内发送的数百万封电子邮件,如果在下午5点时想要查看“我们现在的情况”,我们可以说:
SELECT COUNT(*) FROM dbo.MessageTable WITH (NOLOCK)
WHERE CampaignID = x AND CustomerID = y;
WHERE
子句的情况下使用这个语句来统计 COUNT(*)
。但我认为,如果你愿意接受一些不准确性,也可以这样做:COUNT(*)
。SELECT SUM(rows) FROM sys.partitions
WHERE [object_id] = OBJECT_ID('dbo.tablename')
AND index_id IN (0,1);
由于在飞行中的交易,此数字同样不准确,但实际上并不需要扫描表格,因此效率要高得多。对于我们的情况,即使对于子集,我们也可以使用它:在筛选索引就位(用于其他目的)后,我们可以类似地查询sys.partitions
,但使用筛选索引的index_id
。
然而,在大多数情况下,使用NOLOCK
可能感觉像是一个加速按钮,但它可能造成的不准确性很少值得这样做。除非您的系统已经严重受到tempdb限制,否则应考虑当前场景下使用READ_COMMITTED_SNAPSHOT
而不是NOLOCK
。请参见Read Committed Snapshot的优缺点
SELECT TOP 10 * FROM dbo.MessageLog (NOLOCK) WHERE AppCode = 'DesktopApp' ORDER BY MessageDate DESC
该表的记录主要是写入一次,从不更新。READPAST
提示可以用于仅读取已提交的数据。 - Martin Smith换句话说,当实际上并不需要精确数据时,您正在增加并发性,并且有一些(潜在的)无效数据是可以接受的。
我们有一个表格,保存着一个队列,只会插入和更新内容;从未删除过任何内容。这些行有不同的标志,表示相关进程正在发生什么。生产系统仅使用行锁,但同时在各个行上持有数十个锁,以便不同的进程可以同时进行。
我们检查仍在处理的项目数量,以避免过载系统。当用户启动新进程时,它等待生成子进程,直到队列中当前正在处理的项目少于10个为止。
我们需要防止在可能需要锁定其自身状态以更新其状态的进程上占用锁,并且需要查看已锁定项目的状态。我们使用 with (nolock)
来避免等待查看队列中正在发生的情况,并计算尚未标记为完成的项目数量 - 这由逻辑保证,仅在进程完成时才会发生这种情况。
根据情况,如果您愿意接受一些记录可能已过期的事实,它可以提供更快的访问。
例如:
SELECT COUNT(*) FROM mytable (nolock)
在大型表格上,将使用更少的资源并且通常会更快。
SELECT COUNT(*) FROM mytable
sys.partitions
,它的准确度与SELECT COUNT(*) WITH (NOLOCK)
相当,但速度更快。 - Aaron Bertrand你显然是个天才。但它不应该被使用。
NOLOCK经常被滥用作为加速数据库读取的神奇方法,但我尽可能避免使用它。
结果集可能包含尚未提交的行,这些行通常稍后会被回滚。
错误或结果集可能为空,缺少行或多次显示相同的行。
这是因为其他事务正在同时移动数据,而您正在读取它。
READ COMMITTED还会增加一个问题,即在多个用户同时更改同一单元格的情况下,数据会损坏。
还有其他副作用,这导致了您最初希望获得的速度提升的牺牲。
现在你知道了,永远不要使用它。
我们在具有大量读取但很少写入的表上使用它。如果连接只是读取数据,则通常进行脏读取不会有危险。这可以防止在表上阻塞,从而提高性能。
请查看https://dev59.com/6HM_5IYBdhLWcg3wQQzw#1453000以获取有关nolock及其好坏的更多信息。