一:背景

1. 讲故事

在面试中我相信有很多朋友会被问到 truncate 和 delete 有什么区别 ,这是一个很有意思的话题,本篇我就试着来回答一下,如果下次大家遇到这类问题,我的答案应该可以帮你成功度过吧。

二:区别详解

1. 思考

从宏观角度来说, delete 是 DML 语句, truncate 是 DDL 语句,这些对数据库产生破坏类的语句肯定是要被 sqlserver 跟踪的,言外之意就是在某些场景下可以被回滚的,既然可以被 回滚,那自然就会产生 事务日志,所以从 事务日志 的角度入手会是一个好的办法。

为了方便测试,还是用上一篇的 post 表,创建好之后插入10条记录,参考sql如下:


DROP TABLE dbo.post;
CREATE TABLE post (id INT IDENTITY, content CHAR(1000) DEFAULT 'aaaaaa') INSERT post DEFAULT VALUES
GO 10

有了数据之后就可以通过 fn_dblog 函数从 MyTestDB.ldf 中提取事务日志来观察 delete 和 truncate 日志的不同点。

2. 观察 delete 的事务日志。

为了观察 delete 产生的日志,这里用 @max_lsn 记录一下起始点,参考sql如下:


DECLARE @max_lsn VARCHAR(100)
SELECT @max_lsn=[Current LSN] FROM fn_dblog(NULL,NULL)
DELETE FROM post;
SELECT * FROM fn_dblog(NULL,NULL) WHERE [Current LSN] >@max_lsn

从事务日志看, delete 主要做了两件事情。

  • 10 行 delete 记录删除

这里就有一个好奇的地方了,sqlserver 是如何执行删除操作的呢?要回答这个问题需要到数据页上找答案,参考sql如下:


DBCC IND(MyTestDB,post,-1)
DBCC PAGE(MyTestDB,1,240,2)

从图中可以得到如下两点信息, 至少在堆表下 delete 操作并没有删除 Page,第二个是 delete 记录删除只是将 slot 的指针 抹0 。

有些朋友可能要问,为什么还有对 PFS 的操作呢?很简单它就是用来记录当前页面的 占用空间比率 的,可以看下我的上一篇文章。

3. 观察 truncate 的事务日志。

delete 原理搞清楚之后,接下来看下 truncate 做了什么?参考sql 如下:


DROP TABLE dbo.post;
CREATE TABLE post (id INT IDENTITY, content CHAR(1000) DEFAULT 'aaaaaa') INSERT post DEFAULT VALUES
GO 10 DECLARE @max_lsn VARCHAR(100)
SELECT @max_lsn=[Current LSN] FROM fn_dblog(NULL,NULL)
TRUNCATE TABLE dbo.post
SELECT [Current LSN],Operation,Context,AllocUnitName FROM fn_dblog(NULL,NULL) WHERE [Current LSN] >@max_lsn

从图中可以看到,truncate 主要是对 IAM, PFS, GAM 三个空间管理数据页做了修改,并没有涉及到 PAGE 页,那就有一个疑问了,我的PAGE页还在吗?可以用 DBCC IND 看下。

我去,truncate 操作居然把我的 PAGE 页给弄丢了,它是怎么实现的呢? 要想找到答案,大家可以想一想, truncate 是一个 DDL 语句,为了快速释放表数据,它干脆把 post 和 page 的关系给切断了,如果大家有点懵,画个图大概就是下面这样。

为了验证这个结论,可以用 DBCC PAGE 直接导出 240 号数据页,观察下是不是表中的数据,不过遗憾的是,这个数据页已不归属 post 表了。。。

接下来又得回答另外一个问题,sqlserver 是如何切断的? 这里就需要理解 GAM 空间管理机制。

三:GAM 空间管理

1. 基本原理

GAM 是用来跟踪 区分配 状态的数据页,它是用一个 bit 位跟踪一个 区, 在数据库中一个区表示 连续的8个数据页,在 GAM 数据页中,用 1 表示可分配的初始状态,用 0 表示已分配状态,可能大家有点懵,我再画个简图吧。

为了让大家眼见为实,还是用 post 给大家做个演示。


DROP TABLE dbo.post;
CREATE TABLE post (id INT IDENTITY, content CHAR(1000) DEFAULT 'aaaaaa')
INSERT post DEFAULT VALUES
GO 10 DBCC TRACEON(3604)
DBCC IND(MyTestDB,post,-1)

从图中可以看到,post 表分配的数据页是 240 和 241 号,对应的区号就是 240/8 + 1 = 31,因为 GAM 是用 1bit 来跟踪一个区,所以理论上 GAM 页面偏移 31bit 的位置就标记了该区的分配情况。

这么说可能大家又有点懵,我准备用 windbg 来演示一下,首先大家要记住 GAM 是 mdf 文件中的第三个页面,用 2 表示, 前两个分别是 文件头 和 PFS 页,关于页面的首地址可以用 DBCC PAGE(MyTestDB,1,2,2) 导出来。


0:078> dp 00000009009F8000 +0x60
00000009`009f8060 00000000`005e0000 00000000`00000000
00000009`009f8070 00000000`00000000 00000000`00000000
00000009`009f8080 00000000`00000000 00000000`00000000
00000009`009f8090 00000000`00000000 00000000`00000000
00000009`009f80a0 00000000`00000000 00000000`00000000
00000009`009f80b0 00000000`00000000 00000000`00000000
00000009`009f80c0 d0180000`00001f38 ffffffff`ffffffd1
00000009`009f80d0 ffffffff`ffffffff ffffffff`ffffffff

从输出内容看,那个 0x1f38 就是 bitmap 数组的长度,后面就是 bit 的占用情况,因为在 31 bit 上,我们观察一个 int 就好了,输出如下:

从图中可以看到,全部都是 0 也就说明当前都是分配状态,如果是 1 表示未分配,接下来把 post 给 truncate 掉再次观察 GAM 页。


TRUNCATE TABLE dbo.post;
DBCC PAGE(MyTestDB,1,2,2)

输出如下:


0:117> dp 00000009009F8000+0x60
00000009`009f8060 00000000`005e0000 00000000`00000000
00000009`009f8070 00000000`00000000 00000000`00000000
00000009`009f8080 00000000`00000000 00000000`00000000
00000009`009f8090 00000000`00000000 00000000`00000000
00000009`009f80a0 00000000`00000000 00000000`00000000
00000009`009f80b0 00000000`00000000 00000000`00000000
00000009`009f80c0 d0184000`00001f38 ffffffff`ffffffd1
00000009`009f80d0 ffffffff`ffffffff ffffffff`ffffffff

对比之后会发现由原来的 000000001f38 变成了 400000001f38,可以用 .format 来格式化下。

从图中看 31bit 跟踪的第 31 号区被回收了,也就验证了真的切断了联系。

同样的道理 PFS 偏移的 0n240 位置跟踪的这个页面也是被释放状态。

四:总结

总的来说,delete 操作是将数据页中的每个 slot 指针一条一条的擦掉,每次擦除都会产生一条事务日志,所以对海量数据进行 delete 会产生海量的事务日志,导致你的 日志文件 暴增。而 truncate 是直接切断 post 和 page 的联系,只需要修改几个空间管理页的 bit 位即可。

最后的建议是如果要清空表数据,建议用 truncate table 。

SQLSERVER 的 truncate 和 delete 有区别吗?的更多相关文章

  1. 数据库中truncate与delete的区别与联系

    昨天被问到truncate与delete的区别,truncate没用过,回去百度了一下,才知道还有这个一种语句. truncate table命令将快速删除数据表中的所有记录(保留数据表结构).这种快 ...

  2. MySQL数据库 crud语句 ifnull() 创建新账户 备份数据库 一对多关系 多对多(中间表) 外键约束 自关联 子查询注意事项 DML DDL DQL mysql面试题 truncate与delete的区别

    DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL ...

  3. drop、truncate和delete的区别 [转载]

    drop.truncate和delete的区别 本文转载自: https://www.cnblogs.com/zhizhao/p/7825469.html     (1)DELETE语句执行删除的过程 ...

  4. mysql中 drop、truncate和delete的区别

    mysql中drop.truncate和delete的区别 (1)DELETE语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作. TRUNC ...

  5. mysql之drop、truncate和delete的区别

    今天在整理mysql数据库笔记的时候突然想到一个问题,就是drop.truncate和delete的区别,乍一看三者都是有删除的功能,但是具体来看还是有很多区别的.我先把这三个的作用简单说一下,有前辈 ...

  6. SQL删除语句DROP、TRUNCATE、 DELETE 的区别

    主要介绍了SQL删除语句DROP.TRUNCATE. DELETE 的区别,帮助大家更好的理解和学习sql语句,感兴趣的朋友可以了解下 DROP: 1 DROP TABLE test; 删除表test ...

  7. sql server 中删除表中数据truncate和delete的区别(转载自.net学习网)

    我们都知道truncate table可以用来删除整个表的内容,它与delete后面不跟where条件的效果是一样.但除此之外,我们还清楚它们之间有其它的区别吗?本章我们将一起讨论truncate与d ...

  8. 数据库:drop、truncate、delete的区别

    近日在删除数据时,发现除了常用的Delete & Drop语句之外,还有Truncate也是与删除数据相关的,针对上述三种有进行简单的比较与整理 用法 drop 用法:drop table 表 ...

  9. truncate与delete的区别

    TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同:二者均删除表中的全部行.但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源 ...

  10. drop,truncate与delete的区别

    注意:这里说的delete是指不带where子句的delete语句 相同点 truncate和不带where子句的delete, 以及drop都会删除表内的数据 不同点: 1. truncate和 d ...

随机推荐

  1. 【笔记】CF1714F Build a Tree and That Is It 及相关

    题目传送门 细节较多的构造题. 解决思路 题目中虽然说是无根树,但我们可以钦定这棵树的根为 1,方便构造,这是不影响结果的. 以下记给定的三段长度为 \(a,b,c\) . 先考虑无解的情况. 首先, ...

  2. Mp3文件标签信息读取和写入(Kotlin)

    原文:Mp3文件标签信息读取和写入(Kotlin) - Stars-One的杂货小窝 最近准备抽空完善了自己的星之小说下载器(JavaFx应用 ),发现下载下来的mp3文件没有对应的标签 也是了解可以 ...

  3. JUC学习笔记——共享模型之内存

    JUC学习笔记--共享模型之内存 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的内存部分 我们会分为以下几部分进行介绍: Java内存模型 可见性 模式之两阶段终止 模式之Balk ...

  4. 读书笔记:A Philosophy of Software Design

    今天一位同事在斯坦福的博士生导师John Ousterhout (注,Tcl语言的设计者)来公司做了他的新书<A Philosophy of Software Design>的演讲,介绍了 ...

  5. 【OpenStack云平台】安装Centos操作系统

    视频教程:https://live.csdn.net/v/236820 1.环境准备 准备实验所需要的环境,需要安装VMware Workstation.使用的系统镜像为CentOS-7.5-x86_ ...

  6. php zip下载附件到压缩包并浏览器下载

    /** * 下载图片并生成压缩包 * @param $arr 资源数组 * @return string */ function downloadZipImg($arr) {if(is_array($ ...

  7. 基于LSM树的存储机制简述

    下午听了关于MyRocks-PASV的研究讲座,很有意思所以学习了一下LSM树的一些简单的底层原理.现在整理一下 我们都知道目前Key:Value型的数据库普遍较之关系型数据库有着更好的表现,为什么会 ...

  8. 8.一个项目实战(下载CSDN博客文章)

    专栏地址 ʅ(‾◡◝)ʃ 前言 要写一个下载器,首先要实现一个接口函数,而这个函数可以对请求的数据进行处理也就是爬虫,其次才是写图形化界面 接口的实现 其实CSDN的浏览器页面的接口很复杂,是直接通过 ...

  9. DLR 的扩展库 Dynamitey

    .NET 在 CLR 对动态语言或者脚本语言的支持是通过DLR 完成的, Miguel de Icaza对 DLR 的特点概括如下: 一个针对动态语言的共享式类型系统: 一个共享的 AST,可以被语言 ...

  10. Dev-Cpp下载与安装

    目录 一.介绍 Dev-Cpp 二.下载 Dev-Cpp 1.通过百度网盘下载 2.通过 SourceForge 官网下载 三.安装 Dev-Cpp 写在结尾的话 免责声明 大家好,这里是 main工 ...