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. 将OutLook.exe注册为服务,让其一直保持开启状态

    类似于TaobaoProtect.exe是由TBSecSvc服务启动的 http://stackoverflow.com/questions/3582108/create-windows-servic ...

  2. Android开发之在子线程中使用Toast

    在子线程中使用Toast的时候,出现Force close. 错误提示:Can't create handler inside thread that has not called Looper.pr ...

  3. Hibernate个人总结

    编写Hibernate第一个程序 Hibernate是目前最流行的持久层框架,专注于数据库操作.使用Hibernate框架能够使开发人员从繁琐的SQL语句和复杂的JDBC中解脱出来.Hibernate ...

  4. 如何写mysql的定时任务

     什么是事件: 一组SQL集,用来执行定时任务,跟触发器很像,都是被动执行的,事件是因为时间到了触发执行,而触发器是因为某件事件(增删改)触发执行: 查看是否开启: show variables li ...

  5. 如何把Excel另存为XML格式文件(快速转换)

    这时,我们尝试另存为另一种文件类型: XML电子表格2003(*.xml)

  6. 获取QQ所有的表情包,包括emoji,动态gif

    获取QQ所有的表情包,包括emoji,动态gif,代码如下. <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xht ...

  7. 【 D3.js 高级系列 — 3.0 】 堆栈图

    堆栈图布局(Stack Layout)能够计算二维数组每一数据层的基线,以方便将各数据层叠加起来.本文讲解堆栈图的制作方法. 先说说什么是堆栈图. 例如,有如下情况: 某公司,销售三种产品:个人电脑. ...

  8. Oracle 数据库表空间碎片查询和整理

    dba_free_space 显示的是有free 空间的tablespace ,如果一个tablespace 的free 空间不连续,那每段free空间都会在dba_free_space中存在一条记录 ...

  9. Warning: Name is nonexistent or not a directory

    Every time I start up MATLAB, I receive this message: Warning: Name is nonexistent or not a director ...

  10. JavaEE基本了解

    1.  为什么需要JavaEE 我们编写的JSP代码中,由于大量的显示代码和业务逻辑混淆在一起,彼此嵌套,不利于程序的维护和扩展.当业务需求发生变化的时候,对于程序员和美工都是一个很重的负担. 为了程 ...