表的空间回收是否是表在删除时候就已经回收了呢?
应该和磁盘类似,并不是直接回收,而是标记为可重复利用,一个InnoDB表报包含两个部分,表结构定义和数据
今天并不打算讲解关于表结构的问题,因为表的整体结构来说,在8.0之前,是放在.frm文件中的,在8.0版本之后,可以放在系统数据表中了,所以占用的空间很小
我们主要是针对于表数据的问题,可以放在一个以.idb为后缀的文件中,有时候也会放在共享表空间中,由innodb_file_per_table参数控制
在删除的时候,是如何回收表空间呢?
那就必须说下InnoDB是如何进行的存储,是利用了B+树这种数据结构进行的存储,那么如何删除一条记录呢
如果删除R4,那么直接标记删除即可,但是空间不会腾出来,因为可能还会有数据在300-600之间插入
当然如果一个数据页上所有的数据都被删除了,整个数据页就被标为可以复用了,那么可以在需要新的数据页的时候直接使用,最后,可以延伸上面的结论,在整个表数据都被删除的时候,所有的数据页都会被标为可以复用,但是磁盘并不会变小文件
所以,delete之后并不能减少表的空间,只会标为了可复用,而且在插入和更新的时候,都会造成数据页的复用和删除,在更新的时候,之所以会造成数据页的回收,因为更新就等于删除后插入嘛
那么如何更好的节省表的空间
就是减少数据页的占用,可以利用表的重建,如果有一个表A,需要进行空间的收缩,如何做到呢,如果是自己执行,可以进行新建一个表A结构相同的表B,如果按照主键ID递增,一条条的读出后插入
由于表B示新建的表,所以空洞问题解决了
在MySql中提供了相关的命令
alter table A engine = InnoDB命令来重建表,在MySQL中就是这样和我们自己做的流程一样
当然,如果进行重新插入的时候有新数据的话,可能导致数据的不一致性
于是MySQL从5.6之后,引入了OnlineDDL功能 什么是DDL功能?整体来说在原来基础上进行了优化,现在是建立一个临时文件 扫描A主键的所有数据页
用数据页中表A的记录生成B+树,然后存储到临时文件中
生成临时文件的过程中,所有对A的操作存储到一个日志文件中,
然后临时文件生成后,将日志文件的操作应用到临时文件中,
临时文件替换表A
在上述的online DDL中,MySql也会尝试获取一个写锁,但是写锁在真正的拷贝数据的时候就退化为了读锁,这是为了避免创建临时文件的时候,不会有其他线程进行了DDL
对于一个表来说,DDL最耗时间的操作就是拷贝数据到临时表的过程,这个步骤之间可以进行增删改,但是不能不加读锁,因为不加读锁的时候,其他线程进行了DDL是不可以的
Online和inplace操作之间的区别
Online是一个概念,inplace也是一个概念,两者虽然都是用于拷贝技术,但是并非一个意思
在之前的说法中,将表A的数据拷出来作为tmp_table
这是一个临时表是sever层创建的,但是使用alter方法后,整个临时文件是InnoDB内部自己创建的
对于Server层来说,并没有什么变化 这就是inplace
但是一句话,如果有一个1G的表,磁盘空间只有1.2G 是不能做inplace的,因为临时文件所需的空间不足
alter table t engine = InnoDB其实内部就是
alter table t engine=innodb,ALGORITHM=inplace;
最后一提:alter table是重建一个表
analyze table是重新统计索引信息,加了MDL读锁
optimize table t 等于 recreate + analyze
而alter table在重建表的时候,并不是非常紧凑的,而是会留出1/16的大小给后续的更新使用
所以有时候,重建一个表可能导致占用空间增大