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. 1613. For Fans of Statistics(STL)

    1613 高端的东西 lower_bounder 函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置.如果所有元素都小于val,则返 ...

  2. 关于广义后缀树(多串SAM)的总结

    之前我们给的SAM的例题,基本上是一个串建SAM的就能做的 如果要建多个串的SAM应该怎么做呢 首先看题,bzoj2780 我一开始的想法是SA以前的弄法,把串拼起来,中间加分隔符做SAM 这题确实可 ...

  3. JAVA并发编程学习笔记之ReentrantLock

    ReentrantLock是一个可重入的互斥锁,ReentrantLock由最近成功获取锁,还没有释放的线程所拥有,当锁被另一个线程拥有时,调用lock的线程可以成功获取锁.如果锁已经被当前线程拥有, ...

  4. 【转】 Android中退出程序的提示框

    原文网址:http://blog.csdn.net/jumping_android/article/details/7571309 @Override public boolean onKeyDown ...

  5. Android MVP架构分析

    App架构在Android开发者中一直是讨论比较多的一个话题,目前讨论较多的有MVP.MVVM.Clean这三种.google官方对于架构的态度一直是非常开放的,让开发者自主选择组织和架构app的方式 ...

  6. 关于 mkimage

    在嵌入式系统中,Linux内核和根文件系统一般都与bootloader一起烧写在flash芯片中,系统启动后,bootloader将Linux内核压缩到RAM中,并把压缩的根文件系统复制到RAM中,然 ...

  7. 自杀程序&递归删除目录

    自杀程序,删掉自身,包括执行程序所在的文件夹. 仅在windows下进行了测试,使用语言C# string fileName = Path.GetTempPath() + "killmyse ...

  8. Web网站常规测试方法

    功能测试 1. 安装测试: 安装过程中对于缺省安装目录及任意指定的安装目录,是否都能正确安装: 若是选择安装,查看能否实现其相应的功能: 在所有能中途退出安装的位置退出安装程序后,验证此程序并未安装成 ...

  9. Linux与Windows的8个不同

    (整理来自网络) 对刚刚接触Linux的人来说,很容易从windows的观念去理解Linux系统.今天扒一扒Win和Linux之间常见的8个区别. 一.Linux终端输入密码不回显字符 用户的密码在L ...

  10. windows内核初窥(二)-----系统机制

    系统机制: windows2000为执行体.内核.设备驱动程序等核心态部分提供了一些基础机制.先让我们看看都有哪些: (1)陷阱调度:包括中断.延迟过程调用(DPC).异步过程调用(APC).异常处理 ...