经常会听到一些开发的朋友说,Update语句的操作原理是:先删后加!今天偶然想起这句话,索性验证一下。参考下面示例:
USE CSDN go --新添加一个文件组和文件 ALTER DATABASE CSDN ADD FILEGROUP fg20140313 go ALTER DATABASE CSDN ADD FILE ( NAME = 'fg20140313', FILENAME = 'd:\db\fg20140313.ndf' ) TO FILEGROUP fg20140313 go --创建测试表:UpdatePage IF OBJECT_ID('dbo.UpdatePage', 'U') IS NOT NULL DROP TABLE dbo.UpdatePage GO CREATE TABLE dbo.UpdatePage ( id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, NAME CHAR(10), remark NVARCHAR (200) ) ON fg20140313 GO --插入2条测试数据 INSERT dbo.UpdatePage VALUES('Shawn' , 'This is a test' ) INSERT dbo.UpdatePage VALUES('Lucy' , 'That is a test' ) --此表分配的页情况如下:UpdatePage表分配了一个IAM页(3:9)和一个数据页(3:8) DBCC TRACEON (3604) DBCC IND(CSDN, UpdatePage, 1)
图1. --我们直接看一下8号页上的数据情况,此面包含的2条记录槽号偏移量分别是:96,149 (10进制表示)
DBCC PAGE (CSDN, 3, 8 , 2)
图2.1 --停止SQL SERVER服务,把d:\db\fg20140313.ndf文件Copy出来,用WinHex查看,可以根据槽号来验证一下2条记录的存储位置
图2.2 --启动SQL Server服务,更新定长字段NAME UPDATE dbo.UpdatePage SET NAME = 'xxxx' WHERE ID = 1 --保存数据到硬盘 CHECKPOINT
--查看槽号位置
DBCC PAGE (CSDN, 3, 8 , 2)
图3.1
图3.2 --启动SQL Server服务,更新变长字段remark UPDATE dbo.UpdatePage SET remark = 'remark' WHERE ID = 1 --保存数据到硬盘 CHECKPOINT
DBCC PAGE (CSDN, 3, 8 , 2)
图4.1
图4.2
--启动SQL Server服务,再次更新变长字段remark UPDATE dbo.UpdatePage SET remark = 'This is a long text.' WHERE ID = 1 --保存数据到硬盘 CHECKPOINT
DBCC PAGE (CSDN, 3, 8 , 2)
--结论:
#1.对于更新固定长度的字段,直接update字段值;
#2.对于更新可变长度的字段,当字段存储字符变小时,可能会“先删后加”(这种情况笔者也测试产生过),也可能不会(本例中的就是这种情况)。会的话主要考虑了存储空间的利用,减小碎片;而不会的话,主要考虑了效率。
#3.“先删后加”逻辑上相当于先delete记录再insert记录;物理上并未delete记录,而是更新了Slot中的偏移量并Copy未变化字段Insert到新位置。
#4.从性能上讲,update定长字段的效率会好些.但在设计表时,用定长还是变长字段,还是应该根据业务来定。
#5.最后一句话:Update是“先删后加”不是绝对的。