mysql(六):表数据的删除以及空间回收

场景:
为什么表删掉了一半的数据,表文件的大小还是没变呢?

表数据的存放:
表数据的存放由参数innodb_file_per_table 控制:
① 该参数设置为OFF,表数据放在系统共享表空间,也就是跟数据字典放在一起;
② 设置为ON的时候,每个InnoDB表数据存放在一个以.ibd为后缀的文件中。
从MySQL5.6.6版本开始,默认值就是ON了。
建议这个值设置为ON,因为一个表单独存储为一个文件更容易管理,可以在不需要这个表的时候,通过drop table 命令,系统就会直接删除这个文件。如果放在共享表空间中,即使表删掉了,空间也不会被回收。

我们在删除整个表的时候,可以通过命令 drop table 回收表空间,但是我们遇到的更多是删除某些行,而不是删除一个表。
删除数据流程:
首先我们要删掉某个数据,InnoDB只会把这个记录标记为删除,而不是直接删掉,如果之后再插入一个记录需要才复用这个位置。所以磁盘文件的大小并不会缩小。
而且InnoDB的数据是按页存储的,如果我们删掉了一哥数据页上的所有记录呢?
就是整个数据页都可以被复用,但是跟记录的复用不同的是,记录只限于符合范围的数据才复用。而数据页可以在需要使用新页的时候复用。

如果我们用delete命令把整个表的数据删除呢
结果是所有的数据页都会被标记为可复用。但是磁盘文件大小依旧不会变小。
所以通过 delete命令是不能回收表空间的。 这些可以复用,但是没有被使用的空间,看起来就像是"空洞"。
不止是删除数据会造成空洞,插入数据也会。
底层是B+树,由于某一数据页满了,在插入一个到这数据页时,就需要再新开一个页面,原数据页就可能会留下空洞。
也就是说,经过大量增删改的表,都可能会存在空洞,如果能够把这些空洞去掉。就能达到收缩表空间的目的。
而重建表,就可以达到这样的目的。
重建表
① 可以新建一个与表A结构相同的表B,然后按照主键ID递增的顺序,把数据一行一行的从表A读出来再插入到表B中。
所以表B的主键索引更紧凑,数据页的利用率页更高。从效果上看,就起到了收缩表A空间的作用。
这里可以使用 alter table A engine=InnoDB 命令来重建表。
在MySQL 5.5版本之前,这个命令执行差不多就是跟上面① 描述相同,区别是 表B 不需要自己创建 , MySQL 会自动完成 转存数据、交换表名、删除旧表。
显然,往临时表插入数据的过程比较耗费时间,如果在这个过程中,有新的数据要写入到表A,就会造成数据丢失。所以在这个DDL过程中,表A不能有更新,也就是说,这个DDL不是Online(允许对表做增删改操作)的。
而MySQL 5.6版本就引入了Online DDL,对5.5的这个操作做了优化。
① 建立一个临时文件,扫描表A主键的所有数据页;
② 用数据页中表A的记录生成B+树,存储在临时文件中;
③ 生成临时文件过程中,将所有对A的操作记录在一个日志文件(row log)中;
④ 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个数据上与表A相同的数据文件;
⑤ 用临时文件替换表A的数据文件。
重建表对于大表来说,很消耗IO和CPU资源的,所以如果是线上服务,要小心控制操作时间。可以使用GitHub开源的gh-ost来做。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值