zoukankan      html  css  js  c++  java
  • 注意Sqlserver中使用with(nolock)后实际上还是会加架构锁,只是不对要查询的数据加S锁而已(转载)

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

    • 指定允许脏读。不发布共享锁来阻止其他事务修改当前事务读取的数据,其他事务设置的排他锁不会阻碍当前事务读取锁定数据。允许脏读可能产生较多的并发操作,但其代价是读取以后会被其他事务回滚的数据修改。这可能会使您的事务出错,向用户显示从未提交过的数据,或者导致用户两次看到记录(或根本看不到记录)。有关脏读、不可重复读和幻读的详细信息,请参阅并发影响。
    • READUNCOMMITTED 和 NOLOCK 提示仅适用于数据锁。所有查询(包括那些带有 READUNCOMMITTED 和 NOLOCK 提示的查询)都会在编译和执行过程中获取 Sch-S(架构稳定性)锁。因此,当并发事务持有表的 Sch-M(架构修改)锁时,将阻塞查询。例如,数据定义语言 (DDL) 操作在修改表的架构信息之前获取 Sch-M 锁。所有并发查询(包括那些使用 READUNCOMMITTED 或 NOLOCK 提示运行的查询)都会在尝试获取 Sch-S 锁时被阻塞。相反,持有 Sch-S 锁的查询将阻塞尝试获取 Sch-M 锁的并发事务。有关锁行为的详细信息,请参阅锁兼容性(数据库引擎)。
    • 不能为通过插入、更新或删除操作修改过的表指定 READUNCOMMITTED 和 NOLOCK。SQL Server 查询优化器忽略 FROM 子句中应用于 UPDATE 或 DELETE 语句的目标表的 READUNCOMMITTED 和 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
        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)

    原文链接

  • 相关阅读:
    项目开发中的注意点和技巧
    addslashes — 使用反斜线引用字符串
    PHP error_reporting() 错误控制函数功能详解
    零碎收集cocos知识
    LeetCode:二叉树的前序遍历【144】
    SpringBoot学习笔记:SpringBootAdmin
    LeetCode:简化路径【71】
    LeetCode:组合总数II【40】
    LeetCode:全排列II【47】
    LeetCode:全排列【46】
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/7515805.html
Copyright © 2011-2022 走看看