转载,关于WITH (NOLOCK)的使用


这里明确表示是转载的,如有侵权,我将立即删除

转载两篇关于WITH (NOLOCK)的使用

说实话之前确实没有去认真考虑WITH (NOLOCK)的使用

两篇文章讲的比较好,拿过来分享一下


第一篇来自博客园

http://www.cnblogs.com/henw/archive/2011/07/22/2113580.html

WITH (NOLOCK)

缺点:

  1.会产生脏读

  2.只适用与select查询语句

优点:

  1.有些文件说,加了WITH (NOLOCK)的SQL查询效率可以增加33%。

  2.可以用于inner join 语句

脏读: 一个用户对一个资源做了修改,此时另外一个用户正好读取了这条被修改的记录,然后,第一个用户放弃修改,数据回到修改之前,这两个不同的结果就是脏读。

详细内容:

  要提升SQL的查询效能,一般来说大家会以建立索引(index)为第一考虑。其实除了index的建立之外,当我们在下SQL Command时,在语法中加一段WITH (NOLOCK)可以改善在线大量查询的环境中数据集被LOCK的现象藉此改善查询的效能。

不过有一点千万要注意的就是,WITH (NOLOCK)的SQL SELECT有可能会造成Dirty Read(脏读)。

例如:

SELECT   COUNT (UserID) 
FROM  EMPLOYEE  WITH  (NOLOCK) 
JOIN  WORKING_GROUP  WITH  (NOLOCK) 
ON  EMPLOYEE.UserID  =  WORKING_GROUP.UserID

除了简单的SELECT之外,有JOIN的SELECT语法也是可以使用的。但是DELETE、INSERT、UPDATE这些需要transaction的指令就不行了…


有些文件说,加了WITH (NOLOCK)的SQL查询效率可以增加33%。
加了WITH (NOLOCK)即告诉SQL Server,我们的这段SELECT指令无需去考虑目前table的transaction lock状态,因此效能上会有明显的提升,而且数据库系统的Lock现象会有明显的减少(包含Dead Lock)。

有 一点要特别注意,因为WITH (NOLOCK)不考虑目前table的transaction lock,因此当有某些资料正处于多个phase交易(例如跨多个table的transaction交易-->如提款系统),WITH (NOLOCK)会让目前处理交易process的数据被忽略…

讲白话一点,也就是说当使用NoLock时,它允许阅读那些已经修改但是还没有交易完成的数据。因此如果有需要考虑transaction事务数据的实时完整性时,使用WITH (NOLOCK)就要好好考虑一下。

如果不需考虑transaction,WITH (NOLOCK)或许是个好用的参考。

注1:WITH ( < table_hint > )
指定由查询优化器使用的表扫描、一或多个索引,
或由查询优化器利用此数据表以及为此语句使用锁定模式。

注2:WITH (NOLOCK)相当于READ UNCOMMITTED




另一篇出自

http://www.dotblogs.com.tw/ricochen/archive/2011/04/15/22758.aspx

应该是台湾朋友的,图文并茂,非常好,这里对作者表示感谢



在論壇上看到一則關於With NoLock發問,我不確定發問者是否常態使用NoLock,

但以前經驗告訴我要謹慎使用NoLock,以下就讓我娓娓道來..

2003年微軟有篇關於NoLock的記載,標題如下

NOLOCK 最佳化工具提示可能會造成暫時性的損毀錯誤在 SQL Server 錯誤記錄檔中

image

當時我相當在意圈選中的文字。

當你使用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
 

image

 

現在我來模擬一下並行效果

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()


結果:

image

 

Script1中沒有任何的新增或刪除,但查詢總筆數竟然會得到不同的值,

這些情形就是我前面提到的重複讀取或遺漏讀取..等,

雖然Nolock大部分可以避開Blocking(封鎖)問題,

但Nolock卻也帶來另外一個更麻煩的問題,還請小心服用。

参考http://msdn.microsoft.com/zh-tw/library/ms187373.aspx

SQL Server 中,`WITH (NOLOCK)` 是一种表提示(Table Hint),用于在查询过程中跳过共享锁的获取,从而允许查询读取未提交的数据。这种提示通常用于提高查询性能,特别是在高并发环境中,但同时也会带来数据一致性的风险。 ### 使用方法 `WITH (NOLOCK)` 通常用于 `SELECT` 语句中,附加在表名之后,语法如下: ```sql SELECT column1, column2, ... FROM table_name WITH (NOLOCK) WHERE condition; ``` 可以将其用于多个表连接的查询中,例如: ```sql SELECT t1.column1, t2.column2 FROM table1 t1 WITH (NOLOCK) JOIN table2 t2 WITH (NOLOCK) ON t1.id = t2.t1_id WHERE t1.condition = 'some_value'; ``` ### 示例 以下是一个简单的示例,演示如何在查询中使用 `WITH (NOLOCK)`: ```sql -- 查询订单表,不加锁 SELECT OrderID, CustomerID, OrderDate FROM Orders WITH (NOLOCK) WHERE OrderDate BETWEEN '2023-01-01' AND '2023-12-31'; ``` 在这个例子中,`WITH (NOLOCK)` 被应用在 `Orders` 表上,表示查询将不加共享锁,并允许读取未提交的数据。这可以减少锁等待时间,提高查询速度,但也可能导致脏读(Dirty Read)。 ### 注意事项 - **性能与一致性权衡**:`WITH (NOLOCK)` 可以显著提高查询性能,特别是在高并发环境下,但它可能导致读取到未提交的数据、重复数据或遗漏数据[^3]。 - **适用场景**:适合用于对数据一致性要求不高的报表查询、历史数据分析等场景,而不适合用于需要事务一致性的关键业务逻辑。 - **未来兼容性**:微软建议使用 `WITH (NOLOCK)` 而不是省略 `WITH` 关键字的形式,因为后者可能在未来的 SQL Server 版本中被移除[^1]。 ### 与其他锁提示的比较 SQL Server 提供了多种表提示,例如 `WITH (READPAST)`、`WITH (UPDLOCK)`、`WITH (HOLDLOCK)` 等,用于控制查询时的锁定行为。与 `WITH (NOLOCK)` 不同,这些提示可以用于实现不同的并发控制策略。例如: - `WITH (READPAST)`:跳过被其他事务锁定的行。 - `WITH (UPDLOCK)`:在读取数据时获取更新锁,防止其他事务修改数据。 - `WITH (HOLDLOCK)`:在整个事务中保持共享锁。 ### 示例代码(多表连接) ```sql -- 多表连接使用 WITH (NOLOCK) SELECT o.OrderID, c.CustomerName, o.OrderDate FROM Orders o WITH (NOLOCK) JOIN Customers c WITH (NOLOCK) ON o.CustomerID = c.CustomerID WHERE o.OrderDate >= '2024-01-01'; ``` 此查询将从 `Orders` 和 `Customers` 表中读取数据,而不会对这些表施加共享锁,适用于快速读取但对数据一致性容忍度较高的场景。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值