Update操作一定是先Delete再Insert吗?

Update在数据库中的执行是怎么样的?“Update操作是先把数据删除,然后再插入数据”。在网上看了很多也都是这么认为的。但在查阅到一些不同看法的时候我进行了一些验证,发现还有其它的情况。

这里我分三种情况来讲:

1、更改没有索引列的字段,更改前和更改后的字符串长度一样;
2、更改没有索引列的字段,更改后比更改前的字符串长;
3、更改聚集索引字段。

先准备好数据,以便后面进行对比。

一、创建表、索引和数据:

--创建表MyTable1
IF EXISTS(SELECT * FROM sysobjects WHERE [name]='MyTable1' AND [type]='u')
DROP TABLE MyTable1
GO
CREATE TABLE MyTable1
(
ID INT,
SName VARCHAR(20)
);
--创建索引
CREATE UNIQUE CLUSTERED INDEX IX_ID ON MyTable1(ID); INSERT INTO MyTable1 values( 1,'aaaa')
INSERT INTO MyTable1 values( 2,'bbbb')
INSERT INTO MyTable1 values( 3,'cccc')
GO SELECT * FROM MyTable1 mt
GO --创建表MyTable2
IF EXISTS(SELECT * FROM sysobjects WHERE [name]='MyTable2' AND [type]='u')
DROP TABLE MyTable2
GO
CREATE TABLE MyTable2
(
ID INT,
SName VARCHAR(20)
);
--创建索引
CREATE UNIQUE CLUSTERED INDEX IX_ID ON MyTable2(ID); INSERT INTO MyTable2 VALUES ( 1,'aaaa')
INSERT INTO MyTable2 VALUES ( 2,'bbbb')
INSERT INTO MyTable2 VALUES ( 3,'cccc') SELECT * FROM MyTable2 mt

二、查看数据库的ID号以及两个表对应的ID

--查看数据库的ID号以及两个表对应的ID
select db_id() AS '数据库ID',object_id('MyTable1')as '表MyTable1_ID',object_id('MyTable2')as '表MyTable2_ID'

查询结果如下:

三、查看数据页的页码

--查看数据页的ID
DBCC extentinfo(6,213575799)--这里是刚刚查出来的数据库的ID,是表MyTable1的ID
DBCC extentinfo(6,229575856)--这里是刚刚查出来的数据库的ID,是表MyTable2的ID

查询结果如下:

表示MyTable1的数据存储在第45页,MyTable2的数据存储在第94页。

四、查看2个表所在页面上每条记录的存储情况:

DBCC traceon(3604) WITH NO_INFOMSGS              --打开跟踪
DBCC IND('TestDB','MyTable1',0) --列出所有页和索引。
--参数说明,:数据库名;:表名;:索引的ID,表示堆,-1 表示显示所有索引和IAMs, -2表示只显示IAMs DBCC PAGE(TestDB,1,45,1) --查看数据页和索引
--参数说明,:数据库名;:数据页文件文件组编号;:数据页ID;:数据显示类型(,)

语句执行后我们得到下面的结果:

  1. MyTable1的Row – Offset:

    OFFSET TABLE:
    
    Row - Offset
    2 (0x2) - 134 (0x86)
    1 (0x1) - 115 (0x73)
    0 (0x0) - 96 (0x60)

2、MyTable2的Row – Offset:

OFFSET TABLE:

Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 115 (0x73)
0 (0x0) - 96 (0x60)

可以看到两个表的存储在数据库中数据页的位置是一样的。这是因为一个页只能放一个对象。

五、下面我们来看第一种情况:更改没有索引列的字段,更改前和更改后的字符串长度一样;

UPDATE MyTable1 SET  SName = 'dddd' WHERE ID=2
OFFSET TABLE:
Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 115 (0x73)
0 (0x0) - 96 (0x60)

发现他的存储位置没有发生改变。

再来看MyTable2

--先删除后插入
DELETE FROM MyTable2 WHERE ID=2
INSERT INTO MyTable2(ID,SName)VALUES(2, 'dddd')
OFFSET TABLE:

Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 153 (0x99)
0 (0x0) - 96 (0x60)

表MyTable2的存储发生变化了,原先在115和134之间存储的是第二条记录,现在这条记录却存储到了153个字节以后了,而原来115和134之间什么也没存储,这样这里就形成了内部碎片。对于这种update后数据的存储位置不发生变化的更新称为现场更新,如果位置发生了改变就称为非现场更新。

所以对于这种情形来说:update操作并不是先deleteinsert的。

六、下面我们再来测试第二种情况:更改没有索引列的字段,更改后比更改前的字符串长;

先更新表MyTable1,再查看数据页的存储情况:

UPDATE MyTable1 SET SName='aaaaaa' WHERE ID=2
DBCC PAGE(TestDB,1,45,1)

存储结果如下:

OFFSET TABLE:

Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 153 (0x99)
0 (0x0) - 96 (0x60)

这时我们看到他的存储和先Delete再Insert一样了。

七、我们再来看第三种情况:更改聚集索引字段

为了避免对数据库的操作影响查看的难度,再执行一下创建表的语句。

数据更新之前的结果如下:

MyTable1:
OFFSET TABLE: Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 115 (0x73)
0 (0x0) - 96 (0x60)
MyTable2:
OFFSET TABLE: Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 115 (0x73)
0 (0x0) - 96 (0x60)

先对表MyTable1操作:更新ID(即更新聚集索引列)

UPDATE MyTable1 SET ID = 0 WHERE ID=2
DBCC PAGE(TestDB,1,94,1) --数据页的位置已经发生改变

存储结果如下:

OFFSET TABLE:

Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 153 (0x99)
0 (0x0) - 96 (0x60)

再来对MyTable2操作:

DELETE FROM MyTable2 WHERE ID = 2
INSERT INTO MyTable2(ID,SName)VALUES(2, 'bbbb')
DBCC PAGE(TestDB,1,126,1) --数据页的位置已经发生改变

存储结果如下:

OFFSET TABLE:

Row - Offset
2 (0x2) - 134 (0x86)
1 (0x1) - 153 (0x99)
0 (0x0) - 96 (0x60)

发现此时upadte为非现场更新,数据的存储位置已经发生了改变,和我们所想的先Delete再Insert是一样的。

其实在更改聚集索引键列的时候,也可能发生现场更新。

比如有3条记录分别为1、2、5,我们把其中的2更改为了3,由于3是在1和5之间的数字,所以在更改为3后,这条记录还是会存储在1和5之间,所以就是现场更新了。

Update操作浅析,一定是先Delete再Insert吗?的更多相关文章

  1. 如何让spark sql写mysql的时候支持update操作

    如何让sparkSQL在对接mysql的时候,除了支持:Append.Overwrite.ErrorIfExists.Ignore:还要在支持update操作 1.首先了解背景 spark提供了一个枚 ...

  2. 使用merge同时执行insert和update操作

    SQL点滴18—SqlServer中的merge操作,相当地风骚   今天在一个存储过程中看见了merge这个关键字,第一个想法是,这个是配置管理中的概念吗,把相邻两次的更改合并到一起.后来在tech ...

  3. svn执行update操作后出现:Error : Previous operation has not finished; run 'cleanup' if it was interrupted.

    svn执行update操作后出现:      Error : Previous operation has not finished; run 'cleanup' if it was interrup ...

  4. Oracle merge into 语句进行insert或者update操作,如果存在就update,如果不存在就insert

    merge into的形式:    MERGE INTO [target-table] A USING [source-table sql] B ON([conditional expression] ...

  5. mysql update操作

    update语法 Single-table语法: UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=ex ...

  6. MyBatis魔法堂:各数据库的批量Update操作

    一.前言   MyBatis的update元素的用法与insert元素基本相同,因此本篇不打算重复了.本篇仅记录批量update操作的sql语句,懂得SQL语句,那么MyBatis部分的操作就简单了. ...

  7. Mysql执行Update操作时会锁住表

    update tableA a,(select a.netbar_id,sum(a.reward_amt) reward_amt from tableB a group by a.netbar_id) ...

  8. veridata实验例(5)在更改主键列值,update操作将被分成两个语句

    veridata实验例(5)更改主键列值,update操作将被分成两个语句 续接"veridata实验举例(4)验证veridata查找出updata.delete操作导致的不同步现象&qu ...

  9. spring data jpa的update操作

    简介 使用jpa进行update操作主要有两种方式: 1.调用保存实体的方法 1)保存一个实体:repository.save(T entity) 2)保存多个实体:repository.save(I ...

随机推荐

  1. CodeWars题目筛选

    http://www.codewars.com/kata/search/csharp?q=&r%5B%5D=-8&xids=completed&beta=false 语言选择C ...

  2. vsphere client cd/dvd 驱动器1 正在连接

    esxi 5.1选择了客户端设备,打开控制台后,CD/DVD一直显示“CD/DVD驱动器1 正在连接” 解决方法:vSphere Client客户端问题,关闭和重新打开vSphere Client客户 ...

  3. Android开发之隐式Intent中Intent-filter的三个属性-action,category,data

    使用隐式Intent时,需要使用到意图过滤器Intent-filter.Intent-filter含有三个属性:action,category,data.通过这三个属性的组合,可以启动想要启动的act ...

  4. C++ 类的内存分布

    C++类内存分布 转自:http://www.cnblogs.com/jerry19880126/p/3616999.html   先写下总结,通过总结下面的例子,你就会明白总结了. 下面总结一下: ...

  5. mysql系列命令解释

    mysqld - the MySQL server mysql - the MySQL command-line tool mysqlaccess - client for checking acce ...

  6. html5自带表单验证-美化改造

    神奇的代码 暂且叫做html5.css /* === HTML5 validation styles === */ .myform select:required, .myform input:req ...

  7. SQL Server中Delete语句表名不能用别名

    delete from TABLEA A where A.FIELD1=10        (ORACLE适用)delete TABLEA from TABLEA A where A.FIELD1=1 ...

  8. bzoj1150: [CTSC2007]数据备份Backup

    题目大意: 在n个点中,选出k对相邻的互不相同的点,使k段距离的总和最小. 贪心,双向链表. 首先,点之间的距离是动态的,所以要用堆来维护.   每次都选择最近的点.但因为其他情况,可能最终不会选择这 ...

  9. UVa 1151 (枚举 + MST) Buy or Build

    题意: 平面上有n个点,现在要把它们全部连通起来.现在有q个套餐,如果购买了第i个套餐,则这个套餐中的点全部连通起来.也可以自己单独地建一条边,费用为两点欧几里得距离的平方.求使所有点连通的最小费用. ...

  10. MYSQL学习心得

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...