暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MYSQL-note11, 数据表空间回收

kids and edu 2021-07-06
284

结论:简单地删除表数据达不到表空间回收的效果

 

参数 innodb_file_per_table表数据既可以存在共享表空间里,也可以是单独的文件。这个行为是由参数 innodb_file_per_table 控制的:

1)这个参数设置为 OFF 表示的是,表的数据放在系统共享表空间,也就是跟数据字典放在一起;

2)这个参数设置为 ON 表示的是,每个 InnoDB 表数据存储在一个以 .ibd 为后缀的文件中

从 MySQL 5.6.6 版本开始,它的默认值就是 ON 了。无论哪个版本都建议直接设置称ON,一个表单独存储为一个文件更容易管理,而且在你不需要这个表的时候,通过 drop table 命令,系统就会直接删除这个文件。而如果是放在共享表空间中,即使表删掉了,空间也是不会回收的。

 

delete数据行的操作。InnoDB 里的数据都是用 B+ 树的结构组织的

1,如果删掉某条记录,是把这条记录标记为“删除”,如果下次再在这个中间插入记录,则可以复用。

2,如果是删掉整个数据页,那么整个数据页就可以复用了。以后再插入新数据,可以直接使用这个数据页。

3,如果是删掉整个表的数据,那么所有的数据页都被标记为可以复用,但是空间不会被回收。

delete 命令其实只是把记录的位置,或者数据页标记为了“可复用”,但磁盘文件的大小是不会变的。也就是说,通过 delete 命令是不能回收表空间的。这些可以复用,而没有被使用的空间,看起来就像是“空洞”。

 

插入记录也会造成空洞:如果数据是按照索引递增顺序插入的,那么索引是紧凑的。但如果数据是随机插入的,就可能造成索引的数据页分裂

如果更新索引的值,可以理解为删除一个旧的值,再插入一个新值,也会造成空洞的。

 

 

重建表

1)新建一个与表 A 结构相同的表 B,然后按照主键 ID 递增的顺序,把数据一行一行地从表 A 里读出来再插入到表 B 中。可以使用 alter table A engine=InnoDB 命令来重建表。在 MySQL 5.5 版本之前,这个命令的执行流程跟我们前面描述的差不多,区别只是这个临时表 B 不需要你自己创建,MySQL 会自动完成转存数据、交换表名、删除旧表的操作。如果在这个过程中,有新的数据要写入到表 A 的话,就会造成数据丢失。因此,在整个 DDL 过程中,表 A 中不能有更新。也就是说,这个 DDL 不是 Online 的。

 

2)MySQL 5.6 版本开始引入的 Online DDL,对这个操作流程做了优化。重建表的流程:

2.1)建立一个临时文件,扫描表 A 主键的所有数据页;

2.2)用数据页中表 A 的记录生成 B+ 树,存储到临时文件中;

2.3)生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中;

2.4)临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件;

2.5)用临时文件替换表 A 的数据文件。

由于日志文件记录和重放操作这个功能的存在,这个方案在重建表的过程中,允许对表 A 做增删改操作

 

删除语句在启动的时候需要获取 MDL 写锁,但是这个写锁在真正拷贝数据之前就退化成读锁了。为了实现 Online,MDL 读锁不会阻塞增删改操作,同时禁止其他线程对这个表同时做 DDL。而对于一个大表来说,Online DDL 最耗时的过程就是拷贝数据到临时表的过程,这个步骤的执行期间可以接受增删改操作。所以,相对于整个 DDL 过程来说,锁的时间非常短。对业务来说,就可以认为是 Online 的。

 

 

上述的这些重建方法都会扫描原表数据和构建临时文件,这个操作是很消耗 IO 和 CPU 资源的。因此,如果是线上服务,你要很小心地控制操作时间。如果想要比较安全的操作的话,推荐使用 GitHub 开源的 gh-ost

 

 

 

 

 


文章转载自kids and edu,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论