序言
《MySQL45讲》
为什么表数据删除一半,表文件大小不变?
表数据既可以存在共享表空间里,也可以是单独的文件。这个行为是由参数 innodb_file_per_table
控制的:
-
这个参数设置为 OFF 表示的是,表的数据放在系统共享表空间,也就是跟数据字典放在一起;
-
这个参数设置为 ON 表示的是,每个 InnoDB 表数据存储在一个以 .ibd 为后缀的文件中。
从 MySQL 5.6.6 版本开始,它的默认值就是 ON 了。如果是放在共享表空间中,即使表删掉了,空间也是不会回收的。
假设,我们要删掉 R4 这个记录,InnoDB 引擎只会把 R4 这个记录标记为删除。如果之后要再插入一个 ID 在 300 和 600 之间的记录时,可能会复用这个位置。但是,磁盘文件的大小并不会缩小。
我们知道InnoDB的数据是按页存在,如果一个页上的数据都被删除掉,那么整个页将会被复用。
数据页复用和记录复用是不一样的。
上面的截图而言:
记录复用 – 如果插入一个 ID 是 400 的行,可以直接复用这个空间。但如果插入的是一个 ID 是 800 的行,就不能复用这个位置了。
数据页复用:如果将数据页 page A 上的所有记录删除以后,page A 会被标记为可复用。这时候如果要插入一条 ID=50 的记录需要使用新页的时候,page A 是可以被复用的。
删除数据的过程
- 假设,我们要删掉 R4 这个记录,InnoDB 引擎只会把 R4 这个记录标记为删除。如果之后要再插入一个 ID 在 300 和 600 之间的记录时,可能会复用这个位置。但是,磁盘文件的大小并不会缩小。
如何处理掉因为删除或者插入、更新导致的空洞呢?
方法有三个:
- 使用 alter table A engine=InnoDB 命令来重建表。(recreate)
- analyze table t 其实不是重建表,只是对表的索引信息做重新统计,没有修改数据,这个过程中加了 MDL 读锁;
- optimize table t 等于 recreate+analyze。
参考地址:
https://time.geekbang.org/column/article/72388