概念介绍

开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种。它等同于 READUNCOMMITTED 。 具体的功能作用如下所示(摘自MSDN):

1: 指定允许脏读。不发布共享锁来阻止其他事务修改当前事务读取的数据,其他事务设置的排他锁不会阻碍当前事务读取锁定数据。允许脏读可能产生较多的并发操作,但其代价是读取以后会被其他事务回滚的数据修改。这可能会使您的事务出错,向用户显示从未提交过的数据,或者导致用户两次看到记录(或根本看不到记录)。有关脏读、不可重复读和幻读的详细信息,请参阅并发影响

2: READUNCOMMITTED 和 NOLOCK 提示仅适用于数据锁。所有查询(包括那些带有 READUNCOMMITTED 和 NOLOCK 提示的查询)都会在编译和执行过程中获取 Sch-S(架构稳定性)锁。因此,当并发事务持有表的 Sch-M(架构修改)锁时,将阻塞查询。例如,数据定义语言 (DDL) 操作在修改表的架构信息之前获取 Sch-M 锁。所有并发查询(包括那些使用 READUNCOMMITTED 或 NOLOCK 提示运行的查询)都会在尝试获取 Sch-S 锁时被阻塞。相反,持有 Sch-S 锁的查询将阻塞尝试获取 Sch-M 锁的并发事务。有关锁行为的详细信息,请参阅锁兼容性(数据库引擎)

3:  不能为通过插入、更新或删除操作修改过的表指定 READUNCOMMITTED 和 NOLOCK。SQL Server 查询优化器忽略 FROM 子句中应用于 UPDATE 或 DELETE 语句的目标表的 READUNCOMMITTED 和 NOLOCK 提示。

 

功能与缺陷

使用WIHT(NOLOCK)有利也有弊,所以在决定使用之前,你一定需要了解清楚WITH(NOLOCK)的功能和缺陷,看其是否适合你的业务需求,不要觉得它能提升性能,稀里糊涂的就使用它。

1:使用WITH(NOLOCK)时查询不受其它排他锁阻塞

打开会话窗口1,执行下面脚本,不提交也不回滚事务,模拟事务真在执行过程当中

BEGIN TRAN

 

       UPDATE TEST SET NAME='Timmy' WHERE OBJECT_ID =1;

 

       --ROLLBACK

 

打开会话窗口2,执行下面脚本,你会发现执行结果一直查询不出来(其实才两条记录)。当前会话被阻塞了

SELECT * FROM TEST;

打开会话窗口3,执行下面脚本,查看阻塞情况,你会发现在会话2被会话1给阻塞了,会话2的等待类型为LCK_M_S:“当某任务正在等待获取共享锁时出现”

 

 

  SELECT wt.blocking_session_id                    AS BlockingSessesionId

        ,sp.program_name                           AS ProgramName

        ,COALESCE(sp.LOGINAME, sp.nt_username)     AS HostName    

        ,ec1.client_net_address                    AS ClientIpAddress

        ,db.name                                   AS DatabaseName        

        ,wt.wait_type                              AS WaitType                    

        ,ec1.connect_time                          AS BlockingStartTime

        ,wt.WAIT_DURATION_MS/1000                  AS WaitDuration

        ,ec1.session_id                            AS BlockedSessionId

        ,h1.TEXT                                   AS BlockedSQLText

        ,h2.TEXT                                   AS BlockingSQLText

  FROM sys.dm_tran_locks AS tl

  INNER JOIN sys.databases db

    ON db.database_id = tl.resource_database_id

  INNER JOIN sys.dm_os_waiting_tasks AS wt

    ON tl.lock_owner_address = wt.resource_address

  INNER JOIN sys.dm_exec_connections ec1

    ON ec1.session_id = tl.request_session_id

  INNER JOIN sys.dm_exec_connections ec2

    ON ec2.session_id = wt.blocking_session_id

  LEFT OUTER JOIN master.dbo.sysprocesses sp

    ON SP.spid = wt.blocking_session_id

  CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1

  CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2

此时查看会话1(会话1的会话ID为53,执行脚本1前,可以用SELECT  @@spid查看会话ID)的锁信息情况,你会发现表TEST(ObjId=1893581784)持有的锁信息如下所示

打开会话窗口4,执行下面脚本.你会发现查询结果很快就出来,会话4并不会被会话1阻塞。

SELECT * FROM TEST WITH(NOLOCK)

从上面模拟的这个小例子可以看出,正是由于加上WITH(NOLOCK)提示后,会话1中事务设置的排他锁不会阻碍当前事务读取锁定数据,所以会话4不会被阻塞,从而提升并发时查询性能。

2:WITH(NOLOCK) 不发布共享锁来阻止其他事务修改当前事务读取的数据,这个就不举例子了。

本质上WITH(NOLOCK)是通过减少锁和不受排它锁影响来减少阻塞,从而提高并发时的性能。所谓凡事有利也有弊,WITH(NOLOCK)在提升性能的同时,也会产生脏读现象。

如下所示,表TEST有两条记录,我准备更新OBJECT_ID=1的记录,此时事务既没有提交也没有回滚

BEGIN TRAN 

 

UPDATE TEST SET NAME='Timmy' WHERE OBJECT_ID =1; 

 

--ROLLBACK 

 

此时另外一个会话使用WITH(NOLOCK)查到的记录为未提交的记录值

假如由于某种原因,该事务回滚了,那么我们读取到的OBJECT_ID=1的记录就是一条脏数据。

脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。

WITH(NOLOCK)使用场景

什么时候可以使用WITH(NOLOCK)? 什么时候不能使用WITH(NOLOCK),这个要视你系统业务情况,综合考虑性能情况与业务要求来决定是否使用WITH(NOLOCK), 例如涉及到金融或会计成本之类的系统,出现脏读那是要产生严重问题的。关键业务系统也要慎重考虑。大体来说一般有下面一些场景可以使用WITH(NOLOCK)

1: 基础数据表,这些表的数据很少变更。

2:历史数据表,这些表的数据很少变更。

3:业务允许脏读情况出现涉及的表。

4:数据量超大的表,出于性能考虑,而允许脏读。

另外一点就是不要滥用WITH(NOLOCK),我发现有个奇怪现象,很多开发知道WITH(NOLOCK),但是有不了解脏读,习惯性的使用WITH(NOLOCK)。

WITH(NOLOCK)与 NOLOCK区别

为了搞清楚WITH(NOLOCK)与NOLOCK的区别,我查了大量的资料,我们先看看下面三个SQL语句有啥区别

SELECT * FROM TEST NOLOCK

SELECT * FROM TEST (NOLOCK);

SELECT * FROM TEST WITH(NOLOCK);

上面的问题概括起来也就是说NOLOCK、(NOLOCK)、 WITH(NOLOCK)的区别:

1: NOLOCK这样的写法,其实NOLOCK其实只是别名的作用,而没有任何实质作用。所以不要粗心将(NOLOCK)写成NOLOCK

2:(NOLOCK)与WITH(NOLOCK)其实功能上是一样的。(NOLOCK)只是WITH(NOLOCK)的别名,但是在SQL Server 2008及以后版本中,(NOLOCK)不推荐使用了,"不借助 WITH 关键字指定表提示”的写法已经过时了。 具体参见MSDN http://msdn.microsoft.com/zh-cn/library/ms143729%28SQL.100%29.aspx

2.1  至于网上说WITH(NOLOCK)在SQL SERVER 2000不生效,我验证后发现完全是个谬论。

2.2  在使用链接服务器的SQL当中,(NOLOCK)不会生效,WITH(NOLOCK)才会生效。如下所示

消息 4122,级别 16,状态 1,第 1 行

Remote table-valued function calls are not allowed.

3.语法上有些许出入,如下所示

这种语法会报错

SELECT  * FROM   sys.indexes  WITH(NOLOCK) AS i

-Msg 156, Level 15, State 1, Line 1

-Incorrect syntax near the keyword 'AS'.

 

这种语法正常

SELECT  * FROM   sys.indexes  (NOLOCK) AS i

 

可以全部改写为下面语法

 

SELECT  * FROM   sys.indexes   i WITH(NOLOCK) 

 

 

SELECT  * FROM   sys.indexes   i (NOLOCK) 

WITH(NOLOCK)会不会产生锁

很多人误以为使用了WITH(NOLOCK)后,数据库库不会产生任何锁。实质上,使用了WITH(NOLOCK)后,数据库依然对该表对象生成Sch-S(架构稳定性)锁以及DB类型的共享锁, 如下所示,可以在一个会话中查询一个大表,然后在另外一个会话中查看锁信息(也可以使用SQL Profile查看会话锁信息)

不使用WTIH(NOLOCK)

使用WITH(NOLOCK)

从上可以看出使用WITH(NOLOCK)后,数据库并不是不生成相关锁。  对比可以发现使用WITH(NOLOCK)后,数据库只会生成DB类型的共享锁、以及TAB类型的架构稳定性锁.

另外,使用WITH(NOLOCK)并不是说就不会被其它会话阻塞,依然可能会产生Schema Change Blocking

会话1:执行下面SQL语句,暂时不提交,模拟事务正在执行

BEGIN TRAN 

 

  ALTER TABLE TEST ADD Grade VARCHAR(10) ; 

 

会话2:执行下面语句,你会发现会话被阻塞,截图如下所示。

SELECT * FROM TEST WITH(NOLOCK)

SQL Server 中WITH (NOLOCK)浅析的更多相关文章

  1. (转)SQL Server 中WITH (NOLOCK)浅析

    概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同于 READUNCOMMITTED . 具体的功能作用如 ...

  2. SQL Server 中WITH (NOLOCK)浅析(转潇湘隐者)

    博文出处:http://www.cnblogs.com/kerrycode/p/3946268.html 概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其 ...

  3. [转]SQL Server 中WITH (NOLOCK)浅析

    本文转自:https://www.cnblogs.com/kerrycode/p/3946268.html 概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK) ...

  4. SQL Server 中WITH (NOLOCK)浅析(转)

    概念介绍  开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同于 READUNCOMMITTED . 具体的功能作用 ...

  5. SQL Server 中WITH (NOLOCK)

    with(nolock)的功能: 1: 指定允许脏读.不发布共享锁来阻止其他事务修改当前事务读取的数据,其他事务设置的排他锁不会阻碍当前事务读取锁定数据.允许脏读可能产生较多的并发操作,但其代价是读取 ...

  6. SQL Server 中的 NOLOCK 用法

    大家都知道,每新建一个查询,都相当于创建一个会话,在不同的查询分析器里面进行的操作,可以影响到其他会话的查询,极端的情况可能会一直处于阻塞中,哪怕只是一个很简单的查询都“特别慢”. BEGIN TRA ...

  7. SQL Server 中的 NOLOCK 到底是什么意思?

    以前遇到过,但仅限于听同事说加上NOLOCK好一些,今天仔细研究测试了下,终于理解了,那么加与不加到底区别在哪呢? 我先说下其区别,之后再做测试. 大家都知道,每新建一个查询,都相当于创建一个会话,在 ...

  8. SQL Server中的锁 详解 nolock,rowlock,tablock,xlock,paglock

    摘自: http://www.myexception.cn/sql-server/385562.html 高手进 锁 nolock,rowlock,tablock,xlock,paglock 锁 no ...

  9. 浅析SQL Server 中的SOS_SCHEDULER_YIELD类型的等待

    本文出处:http://www.cnblogs.com/wy123/p/6856802.html 进程的状态转换 在说明SOS_SCHEDULER_YIELD等待之前,先简要介绍一下进程的状态(迷迷糊 ...

随机推荐

  1. (二十一)WebGIS中鹰眼的实现思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 鹰眼功能是WebGIS中的一种常见功能,利用一些开源的框架实现 ...

  2. Linux(Centos)快速搭建SVN

    前言 项目中源码或者文档需要进行管理与版本记录,历数此类工具VSS.CVS.SVN.GIT等等,有非常多的版本控制系统.SVN现在还是很常见,把笔记总结搬上博客,SVN这个再不放以后估计只能写GIT的 ...

  3. TCP滑动窗口机制

    我们可以大概看一下上图的模型: 首先是AB之间三次握手建立TCP连接.在报文的交互过程中,A将自己的缓冲区大小(窗口大小)3发送给B,B同理,这样双方就知道了对端的窗口大小. A开始发送数据,A连续发 ...

  4. 【十大经典数据挖掘算法】kNN

    [十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 1. 引言 顶级数据挖掘会议ICDM ...

  5. 前端读取Excel报表文件

    在实际开发中,经常会遇到导入Excel文件的需求,有的产品人想法更多,想要在前端直接判断文件内容格式是否正确,必填项是否已填写 依据HTML5的FileReader,可以使用新的API打开本地文件(参 ...

  6. 悟透JavaScript

    要理解JavaScript,你得首先放下对象和类的概念,回到数据和代码的本原.前面说过,编程世界只有数据和代码两种基本元素,而这两种元素又有着纠缠不清的关系.JavaScript就是把数据和代码都简化 ...

  7. 策略模式 - Strategy

    Strategy Pattern,定义算法家族,分别封装起来,互相之间可替换,此模式让算法的变化不会影响到使用算法的客户端. // 上下文类(Context):用一个ConcreteStratege来 ...

  8. js自动切换图片

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. CSS3学习总结

    (写在前边~)过了这么长时间,才写博客,最近实在是太忙了,做了两个项目,一个项目用于练手,自我感觉做的很漂亮,一个项目是一套完整的页面体系,答辩时候老师给了100分和99分,并让我打包上传,我很是感动 ...

  10. IDE有毒

    程序员按项目性质大致有三种:写Demo的.写Proto的.写成品的:按项目开发周期大致有:写开头的.写中间的.写结尾的. Demo是样品,主要是表面上初步实现,临时忽悠客户用的,不一定要求继续演化: ...