概念介绍

开发人员喜欢在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 关键字指定表提示”的写法已经过时了。 具体参见MSDNhttp://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)

作者: 潇湘隐者
出处: http://www.cnblogs.com/kerrycode/

如果你真心觉得文章写得不错,而且对你有所帮助,那就不妨小小打赏一下吧,如果囊中羞涩,不妨帮忙“推荐"一下,您的“推荐”和”打赏“将是我最大的写作动力!

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.

SQL Server 中WITH (NOLOCK)浅析(大自然的搬运工)相关推荐

  1. SQL Server 中WITH (NOLOCK)浅析 2014-08-30 11:58 by 潇湘隐者, 58264 阅读, 33 评论, 收藏, 编辑 概念介绍 开发人员喜欢在SQL脚本

    SQL Server 中WITH (NOLOCK)浅析 概念介绍 开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同 ...

  2. SQL Server 中WITH (NOLOCK)浅析

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

  3. 了解SQL Server中NOLOCK和WITH NOLOCK表提示的影响

    Every once in a while, SQL Server database administrators find themselves in disagreements with thei ...

  4. SQL Server 中的事务与事务隔离级别以及如何理解脏读, 未提交读,不可重复读和幻读产生的过程和原因...

    原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...

  5. 在SQL Server中分页结果的最佳方法是什么

    如果您还希望获得结果总数(在进行分页之前),那么在SQL Server 2000.2005.2008.2012中对结果进行分页的最佳方法是(性能明智的)? #1楼 最终, Microsoft SQL ...

  6. SQL Server中的锁类型及用法(转载)

    一. 为什么要引入锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 丢失更新  A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统 脏读  ...

  7. sql server作业_在SQL Server中报告作业失败并发出警报

    sql server作业 SQL Server Agent can be used to run a wide variety of tasks within SQL Server. The buil ...

  8. 如何在SQL Server中分析存储子系统性能

    介绍 (Introduction) To improve performance, it is common for DBAs to search in each aspect except anal ...

  9. SQL Server中的查询优化技术:提示和技巧

    描述 (Description) Fixing bad queries and resolving performance problems can involve hours (or days) o ...

  10. sql 缓冲池_监视SQL Server中的内存文员和缓冲池分配

    sql 缓冲池 The following article applies to SQL Server versions 2008 + 以下文章适用于SQL Server 2008 +版本 Adequ ...

最新文章

  1. java显示链表在jtable上输出_jtable的使用精华
  2. Java基础知识强化之IO流笔记42:IO流总结(图解)
  3. 点云格式解读 PCD
  4. Python基础训练题-简单数学公式
  5. 最短路径之--floyd算法--多源最短路径
  6. 【AIX】AIX 开机自动挂载NFS共享
  7. 【POJ】1276 Cash Machine 【背包问题】
  8. 使用 IntelliTrace 调试应用程序
  9. 小米范工具系列之一:小米范 web查找器
  10. Ajax学习笔记-Ajax的封装-8
  11. POJ 2686 Traveling by Stagecoach
  12. 北京科技大学 工科物理实验 大二下
  13. win10开启Linux蓝屏,win10启动蓝屏_Win10怎么开启蓝屏记录
  14. voip 客户端 android,基于Android平台的VoIP客户端开发与性能改进
  15. 如何了解百度竞价调价技巧
  16. jdk官网_jdk官网下载教程
  17. 一个人一个微博、一个App一个故事:通过微博草根账号做英语学习App的“爱卡微口语”获晨脉创投天使投资
  18. 微博粉丝精灵_天猫精灵“布蕉绿”新品上线,解锁智能音箱潮流新玩法!
  19. js 判断变量是否为空
  20. 安卓 模拟返回按键

热门文章

  1. EventBus源码阅读
  2. vb.net 教程 20-4 库存管理系统3.15 供应商管理(FormSupplier)
  3. [JZOJ 5875] [NOIP2018提高组模拟9.20] 听我说,海蜗牛 解题报告(BFS+二分)
  4. html圆角矩形的渐变色,纯CSS实现圆角渐变三角形
  5. 电壁挂炉一年的费用到底有多少
  6. 今日头条爬美女图片知识点下
  7. PTA团队天梯赛║L1-024 后天
  8. 不能正常访问公司服务器共享文件解决办法【windows 10】
  9. 通过js鼠标移出变绿移入变红和鼠标移入出现提示移出提示消失
  10. 攻防世界-reverserMe WP