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之间,所以就是现场更新了。

时间: 2024-08-22 15:27:17

Update操作一定是先Delete再Insert吗?的相关文章

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

一.前言     MyBatis的update元素的用法与insert元素基本相同,因此本篇不打算重复了.本篇仅记录批量update操作的sql语句,懂得SQL语句,那么MyBatis部分的操作就简单了. 注意:下列批量更新语句都是作为一个事务整体执行,要不全部成功,要不全部回滚.   二.MSSQL的SQL语句 WITH R AS( SELECT 'John' as name, 18 as age, 42 as id UNION ALL SELECT 'Mary' as name, 20 as

各数据库的批量Update操作

一.前言 MyBatis的update元素的用法与insert元素基本相同,因此本篇不打算重复了.本篇仅记录批量update操作的sql语句,懂得SQL语句,那么MyBatis部分的操作就简单了. 注意:下列批量更新语句都是作为一个事务整体执行,要不全部成功,要不全部回滚. 二.MSSQL的SQL语句 WITH R AS( SELECT 'John' as name, 18 as age, 42 as id UNION ALL SELECT 'Mary' as name, 20 as age,

update无效-mybatis+spring+strust2 后update操作不报错但没起效果

问题描述 mybatis+spring+strust2 后update操作不报错但没起效果 日志如上图 sql语句文件如上图 有两个疑问: 1 做insert操作无任何问题,update 操作不报错,就是更新无效果,数据还是原来的数据. 2 sql语句的配置xml文件中判断了if xxx!=null 但是日志里打印出来的sql还是有null (如图2) 解决方案 你的if条件有问题,如果你的参数里面已经有title等参数,就应该写为title!=null而不是带#的 解决方案二: http://

mysql update操作 出现incorrect datetime value

问题描述 mysql update操作 出现incorrect datetime value update iportal_wx.inviterelationshipcycle as A, (select * from iportal_wx.register where register_ctime<current_timestamp() AND register_ctime>ADDDATE(current_timestamp(),-1)) as B set A.IsAttentionHNLL

update操作-出现异常,不进入try,catch代码块怎么办??

问题描述 出现异常,不进入try,catch代码块怎么办?? 我在用hibernate进行update操作的时候,故意制造了值过大的异常,catch(Exception)但是没有进入catch中去,而是直接提示404异常,怎么办??我打算让它返回false,但是现在出现异常直接报出来,没有返回false,直接中断了????怎么办??? 解决方案 catch(throwable)试试 解决方案二: 你先不要制造异常,正常走一遍试试看有没有问题, 没问题的话看看出异常的地方在不在try内 解决方案三

myeclipse maven项目,update 操作时会改变工程的上下文 以及依赖path的jdk

问题描述 myeclipse maven项目,update 操作时会改变工程的上下文 以及依赖path的jdk 求救,如题, myeclipse maven项目,update project configration操作时会改变工程的上下文 以及依赖path的jdk 因为发布到tomcat上且需要作为默认工程发布,开始时候讲工程的上下文 改为"/",每一次做update project configration后上下文 会随之改成工程的名字, 第一次提问,没有分.各位见谅

sql触发器delete与update操作

编写触发器:  代码如下 复制代码 create trigger BlogDelet on Blog instead of delete as delete from Comment where CommentBlog in (select Id from deleted) 创建一个Update触发器:  代码如下 复制代码      Create Trigger truStudent        On Student                         --在Student表中创

一次MSQQL操作的惊险经历,还原恢复update操作!

qq|update|恢复|数据还原 今晚,在批量整理处理时,远程控制服务器的MSSQL查询分析器,可能比较心急手快,在执行一句update时,鼠标才选中了SQL语句的一半时左手就按了执行的F5键(我发誓,以后再也不敢了.),结果一下子把所有四千多条的软件名称记录全部update为[****]了,心想完了完了.. 费了很大的功夫才把这些资料整理好的,一个F5就全完了.. 心想,还有没有什么还原方法呢?第一时间停掉网站的IIS,打开www.baidu.com,真的很感谢百度!尝试搜索关键字:还原 s

ORACLE SQL-UPDATE、DELETE、INSERT优化和使用技巧分享_oracle

UPDATE    1.先备份数据(安全.提高性能). 2.分批更新,小批量提交,防止锁表. 3.如果被更新的自动有索引,更新的数据量很大,先取消索引,再重新创建. 4.全表数据更新,如果表非常大,建议以创建新表的形式替代更新. DELETE 1.分批提交.减少锁表时间.减少回滚段压力. 2.大批量数据删除加上rownum<1000. 3.大批量删除,禁止中途ctrl+c,或kill调session. 4.大量数据删除后最好重建索引,分析表. INSERT    1.关闭redo log(ALT