update值与原值相同时,SQL Server会真的去upda

系统 1937 0
原文: update值与原值相同时,SQL Server会真的去update还是忽略呢?

考虑下面的情况:

当update值与原值相同时,SQL Server会真的去update还是忽略?例如:

      
        update
      
      
         tbname


      
      
        set
      
       name
      
        =
      
      
        '
      
      
        abc
      
      
        '
      
      
        --
      
      
        name原来的值就是abc
      
      
        where
      
       id
      
        =
      
      
        1
      
    

再如:

      
        update
      
      
         tbname


      
      
        set
      
       name
      
        =
      
      
        '
      
      
        abc
      
      
        '
      
      
        --
      
      
        name原来的值就是abc
      
      
        where
      
       name
      
        =
      
      
        '
      
      
        abc
      
      
        '
      
    


接下来我们将实际测试:

      
        --
      
      
        Microsoft SQL Server 2008 R2 (SP1) - 10.50.2500.0 (X64)   Jun 17 2011 00:54:03   Copyright (c) Microsoft Corporation  Enterprise Edition (64-bit) on Windows NT 6.0 <X64> (Build 6002: Service Pack 2) 
      
    

 
1.首先我们先把checkpoint关闭掉,这里用到一个TraceFlog 3505,具体信息参见 这里

      
        DBCC
      
       TRACEON (
      
        3505
      
      );
    

2.准备测试数据:

      
        CREATE
      
      
        DATABASE
      
      
         DB_test 


      
      
        GO
      
      
        USE
      
      
         DB_test


      
      
        GO
      
      
        CREATE
      
      
        TABLE
      
      
         t (

   a 
      
      
        INT
      
      
        ,

   b 
      
      
        CHAR
      
      (
      
        1
      
      
        ),

   
      
      
        CONSTRAINT
      
       PK_t 
      
        PRIMARY
      
      
        KEY
      
      
        CLUSTERED
      
      
         (a)

);

 


      
      
        INSERT
      
      
        INTO
      
       t 
      
        VALUES
      
       (
      
        1
      
      ,
      
        '
      
      
        A
      
      
        '
      
      
        );


      
      
        INSERT
      
      
        INTO
      
       t 
      
        VALUES
      
       (
      
        2
      
      ,
      
        '
      
      
        B
      
      
        '
      
      
        );


      
      
        INSERT
      
      
        INTO
      
       t 
      
        VALUES
      
       (
      
        3
      
      ,
      
        '
      
      
        C
      
      
        '
      
      
        );


      
      
        INSERT
      
      
        INTO
      
       t 
      
        VALUES
      
       (
      
        4
      
      ,
      
        '
      
      
        D
      
      
        '
      
      
        );


      
      
        INSERT
      
      
        INTO
      
       t 
      
        VALUES
      
       (
      
        5
      
      ,
      
        '
      
      
        E
      
      
        '
      
      
        );

 


      
      
        CHECKPOINT
      
      ;
    

3.查看事务日志

      
        SELECT
      
      
        [
      
      
        Current LSN
      
      
        ]
      
      , Operation, Context, 
      
        [
      
      
        Transaction ID
      
      
        ]
      
      
        , AllocUnitName


      
      
        FROM
      
       fn_dblog(
      
        null
      
      , 
      
        null
      
      );
    

得到如下结果:

此处显示的是之前步骤2的checkpoint的记录,此时只有两条记录

4.此时查看刚创建的表的page情况

      
        DBCC
      
       IND (
      
        '
      
      
        DB_test
      
      
        '
      
      ,
      
        '
      
      
        t
      
      
        '
      
      ,
      
        1
      
      );
    

结果:

我们可以看到上面的 page78 是刚才所插入的5条数据所在的page. (PageType=1是DataPage, PageType=10是IAM Page)

5.执行一个update本身的SQL语句,然后再看事务日志,以及内存中的脏数据

      
        UPDATE
      
      
         t


      
      
        SET
      
       b 
      
        =
      
      
        '
      
      
        C
      
      
        '
      
      
        WHERE
      
       a 
      
        =
      
      
        3
      
      
        ;

 


      
      
        --
      
      
         查看日志
      
      
        SELECT
      
      
        [
      
      
        Current LSN
      
      
        ]
      
      , Operation, Context, 
      
        [
      
      
        Transaction ID
      
      
        ]
      
      
        , AllocUnitName


      
      
        FROM
      
       fn_dblog(
      
        null
      
      , 
      
        null
      
      
        );

 


      
      
        --
      
      
         查看脏数据
      
      
        select
      
      
        *
      
      
        from
      
      
         sys.dm_os_buffer_descriptors


      
      
        where
      
       database_id 
      
        =
      
      
        db_id
      
      () 
      
        AND
      
       is_modified 
      
        =
      
      
        1
      
      
        order
      
      
        by
      
       page_id;
    

结果如下:

从上面的结果,我们看到有事务日志的记录,但并不是我们的表t,而是sys.sysobjvalues.clst,它是什么呢?从联机文档查到:

      sys.sysobjvalues   存在于每个数据库中。实体的每个常规值属性均存在对应的一行。
    

从事务日志看,SQL Server并没有真的去update这条记录,然后我们看一下脏数据中是否有对这个page的修改:

从上面看到内存中的被修改的Pageid是152,并不是表t的Page78.

由此我们可以认为SQL Server并不会真的去作一个与原值相同的update操作。

6.如果我们此再更新几个与原值相同的操作,如:

      
        UPDATE
      
      
         t


      
      
        SET
      
       b 
      
        =
      
      
        '
      
      
        D
      
      
        '
      
      
        WHERE
      
       a 
      
        =
      
      
        4
      
      
        ;

 


      
      
        --
      
      
        
          查看日志
        
      
      
        SELECT
      
      
        [
      
      
        Current LSN
      
      
        ]
      
      , Operation, Context, 
      
        [
      
      
        Transaction ID
      
      
        ]
      
      
        , AllocUnitName


      
      
        FROM
      
       fn_dblog(
      
        null
      
      , 
      
        null
      
      
        );

 


      
      
        --
      
      
        
          查看脏数据
        
      
      
        select
      
      
        *
      
      
        from
      
      
         sys.dm_os_buffer_descriptors


      
      
        where
      
       database_id 
      
        =
      
      
        db_id
      
      () 
      
        AND
      
       is_modified 
      
        =
      
      
        1
      
      
        order
      
      
        by
      
       page_id;
    

结果如下:

可以看到事务日志没有增加新的记录,脏数据没有变化,依然是刚才的数据。

7.如果我们此时手动checkpoint,然后再做一个update原值操作呢?

      
        Checkpoint
      
      
        GO
      
      
        UPDATE
      
      
         t


      
      
        SET
      
       b 
      
        =
      
      
        '
      
      
        E
      
      
        '
      
      
        WHERE
      
       a 
      
        =
      
      
        5
      
      
        ;

 


      
      
        --
      
      
        
          查看日志
        
      
      
        SELECT
      
      
        [
      
      
        Current LSN
      
      
        ]
      
      , Operation, Context, 
      
        [
      
      
        Transaction ID
      
      
        ]
      
      
        , AllocUnitName


      
      
        FROM
      
       fn_dblog(
      
        null
      
      , 
      
        null
      
      
        );

 


      
      
        --
      
      
        
          查看脏数据
        
      
      
        select
      
      
        *
      
      
        from
      
      
         sys.dm_os_buffer_descriptors


      
      
        where
      
       database_id 
      
        =
      
      
        db_id
      
      () 
      
        AND
      
       is_modified 
      
        =
      
      
        1
      
      
        order
      
      
        by
      
       page_id;
    

结果如下:

8.如果我们更新一个不同的值,会是什么情况?

      
        UPDATE
      
      
         t


      
      
        SET
      
       b 
      
        =
      
      
        '
      
      
        Z
      
      
        '
      
      
        WHERE
      
       a 
      
        =
      
      
        1
      
      
        ;

 


      
      
        --
      
      
        
          查看日志
        
      
      
        SELECT
      
      
        [
      
      
        Current LSN
      
      
        ]
      
      , Operation, Context, 
      
        [
      
      
        Transaction ID
      
      
        ]
      
      
        , AllocUnitName


      
      
        FROM
      
       fn_dblog(
      
        null
      
      , 
      
        null
      
      
        );

 


      
      
        --
      
      
        
          查看脏数据
        
      
      
        select
      
      
        *
      
      
        from
      
      
         sys.dm_os_buffer_descriptors


      
      
        where
      
       database_id 
      
        =
      
      
        db_id
      
      () 
      
        AND
      
       is_modified 
      
        =
      
      
        1
      
      
        order
      
      
        by
      
       page_id;
    

结果如下:

我们可以很清楚的看到它的update的Log以及脏数据page.

9.所以,由上面的多个测试结果可以看出,如果update的值与原值相同,SQL Server并不会真的去做一个这样的操作,而是忽略掉了。

10.通过工具ApexSQL也可以证明这个结论,它只记录了insert和最后一次update;

11.最后,记得DBCC TRACEOFF (3505);


此文基本参考: http://www.bobpusateri.com/archive/2010/10/updates-that-really-arent/

 

 

 

 

update值与原值相同时,SQL Server会真的去update还是忽略呢?


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论