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

原文: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/

 

 

 

 

时间: 2024-09-28 05:39:44

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

SQL Server 致程序员(容易忽略的错误)

原文:SQL Server 致程序员(容易忽略的错误) 标签:SQL SERVER/MSSQL/DBA/T-SQL好习惯/数据库/需要注意的地方/程序员/容易犯的错误/遇到的问题 概述 因为每天需要审核程序员发布的SQL语句,所以收集了一些程序员的一些常见问题,还有一些平时收集的其它一些问题,这也是很多人容易忽视的问题,在以后收集到的问题会补充在文章末尾,欢迎关注,由于收集的问题很多是针对于生产数据,测试且数据量比较大,这里就不把数据共享出来了,大家理解意思就行.   步骤 大小写 大写T-SQ

SQL Server ltrim(rtrim()) 去不掉空格的原因分析

原因:中间存在回车符或者换行符,所以要先将此符号替换掉: LTRIM(RTRIM(REPLACE(REPLACE( A,char(13),''),char(10),'') )) LTRIM(A) ---去换左边空格 RTRIM(A) ---去换右边空格 REPLACE( A,char(13),'')----将回车符替换为'' REPLACE( A,char(13),'')----将换行符替换为'' 总结 以上所述是小编给大家介绍的SQL Server ltrim(rtrim()) 去不掉空格的原

简述SQL SERVER触发器内INSERT,UPDATE,DELETE的三种状态

一个触发器内三种INSERT,UPDATE,DELETE状态 CREATE   TRIGGER   tr_T_A   ON     T_A   for   INSERT,UPDATE,DELETE        如IF   exists   (select   *   from   inserted)   and   not   exists   (select   *   from   deleted)   则为   INSERT  如IF   exists(select   *   from

sql server 2008 r2-SQL去计算一位小数的问题

问题描述 SQL去计算一位小数的问题 表字段为int类型 CASE WHEN MyRequiredPeriod IS NULL THEN '-' ELSE CAST(ROUND(MyRequiredPeriod/3600,1) AS NVARCHAR(50)) END,这样取出来的小数后面带0,怎样才让能让这个字段取得两位小数呢 解决方案 http://blog.itpub.net/22392018/year-201405-list-1/ 解决方案二: CASE WHEN MyRequiredP

SQL Server 2012 自动增长列,值跳跃问题

原文:SQL Server 2012 自动增长列,值跳跃问题   介绍 从 SQL Server 2012 版本开始, 当SQL Server 实例重启之后,表格的自动增长列的值会发生跳跃,而具体的跳跃值的大小是根据增长列的数据类型而定的.如果数据类型是 整型(int),那么跳跃值为 1000:如果数据类型为 长整型(bigint),那么跳跃值为 10000.从我们的项目来看,这种跳跃问题是不能被接受的,尤其是展示在客户端的时候.这个奇怪的问题只在 SQL Server 2012 及更高的版本中

SQL server 2012数据库某字段超过某个值短信提醒?

问题描述 SQL server 2012数据库某字段超过某个值短信提醒? SQL server 2012数据库某字段超过某个值短信提醒? 解决方案 这个问题有人问过了,我详细回答过了,移步http://ask.csdn.net/questions/235536 解决方案二: 给手机发送短信,是要通过运营商提供接口的. 解决方案三: 设置触发器,发现符合某个条件了,调用程序,然后程序再进行短信发送处理 解决方案四: 可以通过创建存储过程,由存储过程发送短信请求,触发器生成url参数,调用存储过程的

SQL Server 2005 中的批编译、重新编译和计划缓存问题(2)

查询计划缓存及各种 SET 选项(与 showplan 相关及其他) 各种 SET 选项--多数与 showplan 相关--以多种复杂的方式影响着查询计划和执行上下文的编译.缓存和重用.下表汇总了相关的详细信息. 应按如下顺序阅读该表中的内容.批处理通过表中第一列所指定的特定模式提交给 SQL Server.已提交的批处理的计划缓存中可能存在.也可能不存在已缓存的查询计划.第 2 列和第 3 列描述了存在已缓存的查询计划时的情况:第 4 列和第 5 列说明了不存在已缓存的查询计划时的情况.在每

把Oracle数据库移植到Microsoft SQL Server 7.0

oracle|server|数据|数据库  把Oracle数据库移植到Microsoft SQL Server 7.0 摘要:本文是为那些想把自己的Oracle应用程序转换为Microsoft SQL Server应用程序的开发人员编写的.本文描述了一个成功的转换所需要的工具.过程和技术.同时强调了建立高性能.高度并行的SQL Server应用程序的基本的设计要素. 本文的读者应该具有: Oracle关系型数据管理系统(RDBMS)的坚实基础. 普通数据库管理知识. 熟悉Oracle SQL和P

SQL Server · 特性分析 · 2012列存储索引技术

摘要 MS SQL Server 2012首次引入了列存储索引(Columnstore Index)来加速数据分析(OLAP)和数据仓库(Data Warehouse)场景的查询,它主要是通过将数据按列压缩存储的方式来减少查询对磁盘IOPS开销和CPU开销,最终达到提升查询效率,降低响应时间的目的.当然,列存储索引也不是一把万能的钥匙,在SQL Server 2012版本中它有诸多非常严苛限制条件. 这篇文章会从以下几个方面来介绍列存储索引: 列存储索引所涉及到的基本概念 列存储索引的结构 列存