继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

delete 清空表之后,磁盘空间未发生变化?

江南一点雨
关注TA
已关注
手记 318
粉丝 1.4万
获赞 3885

上篇文章结尾和小伙伴们留了一个小问题,就是关于 optimize table 命令,今天我想花点时间再来和小伙伴们聊一聊这个话题。

1. 删除空洞

1.1 案例展示

首先我们先来看这样一个例子。

我现在有一个名为 sakila 的数据库,该库中有一个 film 表,这个表中有 1000 条记录,我么先来看下这 1000 条记录占用了多少存储空间:

小伙伴们可以看到,这个文件大小是 360448 个字节。

我们现在执行 delete 命令将这个表清空:

delete from film;

然后再来查看这个文件的大小:

小伙伴们看到,这个表中的数据没有减少,甚至还增加了!这是咋回事?

1.2 分析

以下所说的删除皆指通过 delete 命令删除,不包括通过 truncate/drop 删除。

MySQL 中的数据删除操作有点像我们平日里做业务开发时用的逻辑删除,当你想要删除掉一行数据的时候,这行数据其实并没有被真正的删除掉,只是暂时给标记为删除了而已。

经过前面文章的介绍,小伙伴们应该已经清楚,MySQL 表中的数据最终是以 B+Tree 的形式保存在磁盘中的,当你要删除一条记录的时候,那么对应的叶子上的数据就会被标记为已删除,类似下面这样:

当 ID 为 6 的记录被删除掉之后,这块空间并不会立马被释放出来,MySQL 只是在这个位置做一个删除标记,将来要是还有一个 ID 为 6 的数据被插入进来,就会插入到这里。

因此我们看到,一张表在经过 N 多次删除之后,就会出现大量这种情况,这种就称之为删除空洞。

2. 插入空洞

前面所说的删除会造成空洞,其实插入也会造成空洞。

松哥在之前的文章中和小伙伴们分享过,InnoDB 引擎的表中不建议使用随机字符串作为 ID,因为随机字符串插入会造成页分裂。页分裂之后,在分裂之前的叶子中,也有可能会空出来新的空间,造成空洞。

例如下面这个例子:

在上图这个 B+Tree 中,继续插入 5,就会造成页分裂,页分裂之后,2 所在的数据页(InnoDB 操作磁盘的最小单位是数据页)就会有空余,这也是空洞的一种。

当然更新索引上的值也会造成空洞,因为更新相当于插入+删除。

3. optimize table

想要解决这个问题,我们可以使用 optimize table 命令来实现。该命令可以用来重新整理表空间,并优化文件碎片。接下来我们针对前面 1.1 小节中的案例,来试试 optimize table 命令是否有效:

这上面有一句提示,说 Table does not support optimize, doing recreate + analyze instead,看这个意思,似乎是说当前这个 InndoDB 引擎的表不支持 optimize 操作,不过我们不用管,我们现在去查看表文件大小:

可以看到,表文件数据其实已经减少了。

那么这句提示是咋回事呢?

我们以 MySQL 官方文档介绍为准来看下:

从这段话中可以看到,在 InnoDB 中使用 optimize 命令,相关的操作最终会被映射为 alter table ...,这个操作松哥在上篇文章中和小伙伴们介绍过了,这也可以实现索引的重整并且释放掉未使用的空间,所以,网上有人说 optimize table 命令不适用于 InnoDB 引擎的表这个说法是不正确的。

同时,官方文档中这段介绍还提到了 optimize 操作是 online DDL 的。online DDL 意味着在执行 optimize 重整表的时候,并不会阻塞正在进行的 CURD 操作。具体流程如下:

  1. 首先建立一个临时文件,这个临时文件用来扫描表原始表主键的所有数据页。
  2. 根据第一步获取到的表记录生成一个 B+Tree,将这个生成的 B+Tree 存储到临时文件中。
  3. 由于第二步会比较耗时,在第二步执行过程中,如果有针对原始表的 CRUD 操作,则先将操作记录到一个日志文件中,等到第二步的临时文件生成后,在把日志文件应用到临时文件中,就可以获取到一个最新的数据表了。

好啦,这就是关于 optimize table 的操作细节,小伙伴们 GET 到了吧~

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP