[SQL SERVER][Performance]小心使用With NoLock

[SQL SERVER][Performance]小心使用With NoLock


在论坛上看到一则关于With NoLock发问,我不确定发问者是否常态使用NoLock,

但以前经验告诉我要谨慎使用NoLock,以下就让我娓娓道来..

2003年微软有篇关于NoLock的记载,标题如下

NOLOCK 最佳化工具提示可能会造成暂时性的损毁错误在 SQL Server 错误记录档中

[SQL SERVER][Performance]小心使用With NoLock

当时我相当在意圈选中的文字。

当你使用NoLock时,你等于是告诉SQL Server 使用者不在意数据正确性和一致性,

假设某位使用者正在更新数据表,就会影响其他使用者查询(with nolock)该数据的正确性和一致性,

那些查询的使用者可能会遇到重复读取相同数据、遗漏读取或中途读取..等状况,

而我更在意页面分割的动作

(页面分割这里不多叙述,但你可以参考2011年4月 RUN!PC我所发表的索引概念和设计)

我只和你说页面分割是相当耗费系统资源的动作,

你绝对不希望使用者再查询数据时,还得同时处理页面分割动作,

所以无论如何请一定要减少页面分割发生的频率。

Note:

NoLock和ReadUnCommitted效果一样。

create table mytest
(id int identity not null,
data uniqueidentifier default(newid()) not null 
)
--新增数据
declare @i int;set @i=1;
while @i<=30000
begin
insert mytest default values  
set @i=@i+1
end
--建立唯一丛集索引
create unique clustered index cidx on mytest( data )
--确认使用空间
exec sp_spaceused mytest
go

[SQL SERVER][Performance]小心使用With NoLock

现在我来模拟一下并行效果

Connection1执行以下Script1

declare @totalrows int
,@currentnow int
,@errorcount tinyint
 
set @errorcount = 0
select @totalrows= count(1) from mytest 

while 1 = 1
begin
    --waitfor delay '00:00:00.200'
    select @currentnow= count(1) from mytest WITH(NOLOCK,INDEX = cidx )  
    if @totalrows <> @currentnow
    begin
        print '现在查询总笔数= ' + cast( @currentnow as varchar(10) ) + 
        ' 差异笔数= ' + cast( @currentnow - @totalrows as varchar(10) )
        set @errorcount = @errorcount + 1
        if @errorcount >= 8
            break
    end
end



Connection2执行以下Script2

begin tran mytran
update mytest
    set data = newid()

结果:

[SQL SERVER][Performance]小心使用With NoLock

Script1中没有任何的新增或删除,但查询总笔数竟然会得到不同的值,

这些情形就是我前面提到的重复读取或遗漏读取..等,

虽然Nolock大部分可以避开Blocking(*)问题,

但Nolock却也带来另外一个更麻烦的问题,还请小心服用。

参考

并行效果

数据表提示 (Transact-SQL)

原文:大专栏  [SQL SERVER][Performance]小心使用With NoLock


上一篇:多租户系统中如何实现分别限流


下一篇:Sql Server之旅——终点站 nolock引发的三级事件的一些思考