数据库中收缩表空间的方法,重建表的方法
表数据可以存在共享表空间里,也可以是单独的文件。由参数 innodb_file_per_table控制:
这个参数设置为OFF表示的是,表的数据放在系统共享表空间,也就是跟数据字典放在一 起
这个参数设置为ON表示的是,每个InnoDB表数据存储在一个以 .ibd为后缀的文件中。
从MySQL 5.6.6版本开始,它的默认值就是ON了。
建议将这个值设置为ON。因为,一个表单独存储为一个文件更容易管理,而且在不需要这个表的时候,通过drop table命令,系统就会直接删除这个文件。而如果是放在共享表空间中,即使表删掉了,空间也是不会回收的。
InnoDB的索引结构为B+树。假设,要删掉R4这个记录,InnoDB引擎只会把R4这个记录标记为删除。如果之后要再插入 一个ID在R4前后记录之间的记录时,可能会复用这个位置。但是,磁盘文件的大小并不会缩小 。
数据页的复用跟记录的复用是不同的:
用delete命令把整个表的数据删除,所有的数据页都会被标记为可复用。但是磁盘上,文件不会变小 。 也就是说,通过delete命令是不能回收表空间的 。
删除,插入,更新数据会造成“空洞”( 可以复用,而没有被使用的空间 )。
如果数据是按照索引递增顺序插入的,那么索引是紧凑的。但如果数据是随机插入的,就可能造 成索引的数据页分裂。
使用
alter table A engine=InnoDB命令来重建表
经过大量增删改的表,都是可能是存在空洞的。所以,如果能够把这些空洞去掉,就能达到收缩表空间的目的。 而重建表,就可以达到这样的目的。
新建一个与表A结构相同的表B,然后按照主键ID递增的顺序,把数据一行一行地从表A 里读出来再插入到表B中。
由于表B是新建的表,所以表A主键索引上的空洞,在表B中就都不存在了。显然地,表B的主键 索引更紧凑,数据页的利用率也更高。如果我们把表B作为临时表,数据从表A导入表B的操作完 成后,用表B替换A,从效果上看,就起到了收缩表A空间的作用。
使用alter table A engine=InnoDB命令来重建表,花时间最多的步骤是往临时表插入数据的过程 。 在MySQL 5.5版本之前执行命令(改锁表DDL, 表A中不能有更新),MySQL会自动完成转存数据、交换表名、删除旧表的操作。
在MySQL 5.6版本开始引入的Online DDL,对这个操作流程做了优化。
引入了Online DDL之后,重建表的流程 :
- 建立一个临时文件,扫描表A主键的所有数据页;
- 用数据页中表A的记录生成B+树,存储到临时文件中;
- 生成临时文件的过程中,将所有对A的操作记录在一个日志文件(row log)中;
- 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表A相同的 数据文件;
- 用临时文件替换表A的数据文件
两者不同之处在于,由于日志文件记录和重放操作这个功能,在重建表的过程中,允许对表A做增删改操作。这也就是Online DDL名字的来源。
这些重建方法都会扫描原表数据和构建临时文件。对于很大的表来说,这个操作是很消耗IO和CPU资源的 。
重建表的这个语句alter table t engine=InnoDB,其实隐含的意思是: alter table t engine=innodb,ALGORITHM=inplace; 使用ALGORITHM=copy的时候,表示的是强制拷贝表
Online 和 inplace 这两个逻辑之间的关系 :
optimize table、analyze table和alter table这三种方式重建表的区别:
alter table t engine = InnoDB(也就是recreate)默认的就是的Online DDL流程了;analyze table t 其实不是重建表,只是对表的索引信息做重新统计,没有修改数据,这个过程中加了MDL读锁;optimize table t 等于recreate + analyze。alter table命令重建表,才能达到表文件变小的目的