13 | 为什么表数据删掉一半,表文件大小不变?
Page content
13 | 为什么表数据删掉一半,表文件大小不变?
表数据的存储
- 存储在共享表空间里
- 存储在单独的文件
通过innodb_file_per_table
参数控制,且5.6.6开始,默认为 on
推荐设置为 on,单独存储易管理,执行 drop table 命令,系统会直接删除表对应的文件,如果存放在共享表里则不会删除
为什么删除数据,文件大小不变
前置须知:InnoDB 的数据模型是 B+ 树
执行删除操作后,对应的记录不会被真正的删除,仅仅是标记此条记录原本存在的位置可复用,如果恰好有一条数据需要插入到此位置,则复用,否则它就一直存在,像一个“空洞”;
如果是整页数据被删除,也是采用标记的形式,不会真正删除,只是这一页下次被使用时,位置可以改变,不局限于原来的位置。
类似的还有插入和更新操作,都会导致“空洞”,这些空洞就是导致删除记录,但文件大小不变但原因。
通过重建表,优化“空洞”问题
alter table A engine=InnoDB
- 建立一个临时文件,扫描表 A 主键的所有数据页;
- 用数据页中表 A 的记录生成 B+ 树,存储到临时文件中;
- 生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中,对应的是图中 state2 的状态;
- 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件,对应的就是图中 state3 的状态;
- 用临时文件替换表 A 的数据文件。
问题讨论
假设现在有人碰到了一个“想要收缩表空间,结果适得其反”的情况,看上去是这样的:一个表 t 文件大小为 1TB;对这个表执行 alter table t engine=InnoDB;发现执行完成后,空间不仅没变小,还稍微大了一点儿,比如变成了 1.01TB。你觉得可能是什么原因呢 ?
答案 表本身就已经没有空洞的了,比如说刚刚做过一次重建表操作。在 DDL 期间,如果刚好有外部的 DML 在执行,这期间可能会引入一些新的空洞。