Update操作浅析,一定是先Delete再Insert吗?
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;:数据显示类型(,)
语句执行后我们得到下面的结果:
- 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操作并不是先delete后insert的。
六、下面我们再来测试第二种情况:更改没有索引列的字段,更改后比更改前的字符串长;
先更新表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吗?的更多相关文章
- 如何让spark sql写mysql的时候支持update操作
如何让sparkSQL在对接mysql的时候,除了支持:Append.Overwrite.ErrorIfExists.Ignore:还要在支持update操作 1.首先了解背景 spark提供了一个枚 ...
- 使用merge同时执行insert和update操作
SQL点滴18—SqlServer中的merge操作,相当地风骚 今天在一个存储过程中看见了merge这个关键字,第一个想法是,这个是配置管理中的概念吗,把相邻两次的更改合并到一起.后来在tech ...
- 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 ...
- Oracle merge into 语句进行insert或者update操作,如果存在就update,如果不存在就insert
merge into的形式: MERGE INTO [target-table] A USING [source-table sql] B ON([conditional expression] ...
- mysql update操作
update语法 Single-table语法: UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=ex ...
- MyBatis魔法堂:各数据库的批量Update操作
一.前言 MyBatis的update元素的用法与insert元素基本相同,因此本篇不打算重复了.本篇仅记录批量update操作的sql语句,懂得SQL语句,那么MyBatis部分的操作就简单了. ...
- Mysql执行Update操作时会锁住表
update tableA a,(select a.netbar_id,sum(a.reward_amt) reward_amt from tableB a group by a.netbar_id) ...
- veridata实验例(5)在更改主键列值,update操作将被分成两个语句
veridata实验例(5)更改主键列值,update操作将被分成两个语句 续接"veridata实验举例(4)验证veridata查找出updata.delete操作导致的不同步现象&qu ...
- spring data jpa的update操作
简介 使用jpa进行update操作主要有两种方式: 1.调用保存实体的方法 1)保存一个实体:repository.save(T entity) 2)保存多个实体:repository.save(I ...
随机推荐
- 1613. For Fans of Statistics(STL)
1613 高端的东西 lower_bounder 函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置.如果所有元素都小于val,则返 ...
- 关于广义后缀树(多串SAM)的总结
之前我们给的SAM的例题,基本上是一个串建SAM的就能做的 如果要建多个串的SAM应该怎么做呢 首先看题,bzoj2780 我一开始的想法是SA以前的弄法,把串拼起来,中间加分隔符做SAM 这题确实可 ...
- JAVA并发编程学习笔记之ReentrantLock
ReentrantLock是一个可重入的互斥锁,ReentrantLock由最近成功获取锁,还没有释放的线程所拥有,当锁被另一个线程拥有时,调用lock的线程可以成功获取锁.如果锁已经被当前线程拥有, ...
- 【转】 Android中退出程序的提示框
原文网址:http://blog.csdn.net/jumping_android/article/details/7571309 @Override public boolean onKeyDown ...
- Android MVP架构分析
App架构在Android开发者中一直是讨论比较多的一个话题,目前讨论较多的有MVP.MVVM.Clean这三种.google官方对于架构的态度一直是非常开放的,让开发者自主选择组织和架构app的方式 ...
- 关于 mkimage
在嵌入式系统中,Linux内核和根文件系统一般都与bootloader一起烧写在flash芯片中,系统启动后,bootloader将Linux内核压缩到RAM中,并把压缩的根文件系统复制到RAM中,然 ...
- 自杀程序&递归删除目录
自杀程序,删掉自身,包括执行程序所在的文件夹. 仅在windows下进行了测试,使用语言C# string fileName = Path.GetTempPath() + "killmyse ...
- Web网站常规测试方法
功能测试 1. 安装测试: 安装过程中对于缺省安装目录及任意指定的安装目录,是否都能正确安装: 若是选择安装,查看能否实现其相应的功能: 在所有能中途退出安装的位置退出安装程序后,验证此程序并未安装成 ...
- Linux与Windows的8个不同
(整理来自网络) 对刚刚接触Linux的人来说,很容易从windows的观念去理解Linux系统.今天扒一扒Win和Linux之间常见的8个区别. 一.Linux终端输入密码不回显字符 用户的密码在L ...
- windows内核初窥(二)-----系统机制
系统机制: windows2000为执行体.内核.设备驱动程序等核心态部分提供了一些基础机制.先让我们看看都有哪些: (1)陷阱调度:包括中断.延迟过程调用(DPC).异步过程调用(APC).异常处理 ...