1、现象
这个表目前 占用了1.3g左右的磁盘空间,总条数为4000000左右。很显然,我不想要指明多日志数据,我想删除掉很早之前的,保留最近的
占用磁盘存储 没降反升!!!
2、原因
在InnoDB中,delete操作并不会真的删除数据,mysql实际上只是给要删除的数据打了标记,标记为删除。磁盘所占空间不会变小,有可能还会变大,即表空间并没有真正被释放。
2.1、mysql 设计者为什么不删掉数据?留着不是占用磁盘嘛!
1、重构索引,会导致磁盘IO,如果数据在磁盘上移除之后,很多其它的记录需要在磁盘上重新排列,这会消耗大量的性能。(例如:一个大表,存在索引,删除了其中一行,那么整个索引结构就会发生变化,随之而来的改变索引结构,必将带来磁盘IO),删除中间数据记录如果真正的删除磁盘数据,mysql会重构索引,因为innodb引擎主键索引树叶子节点才真正存储数据,主键索引树按顺序排序,中间数据删除,必然会导致重建索引树啊,索引树存储在磁盘,不就导致大量磁盘IO嘛
2、提升效率,重用空间,覆盖被标识删除的数据,所有被删除的记录会组成一个垃圾链表,这个链表记录占用的空间叫可重用空间。新插入的记录可覆盖此空间。
2.2、表空间如何复用
记录复用
id为10-100之间的数据,删除id=20的记录,这条记录被标记为删除。下次如有id=30的记录要插入,可以复用此Id=20被标记删除的位置。
id=30 不是应该覆盖原来id=30的嘛?一般来说是的,但数据插入并不一定一自增的方式插入,原来id=30的位置可能并没有数据,数据插入之前进行比较10<30<100 ,期间发现id=20所在节点被标识删除,直接就会覆盖
数据页复用
这种情况是指整个数据页都被标记为删除,所以整个数据页都可以被复用了。和行记录复用不同,数据页复用对要插入的数据几乎没有条件限制。
2.3、被标识删除的数据怎么办,虽然不删除效率会提升,但一直留着不是占用磁盘空间嘛,数据是一直增长的呀!
被标记为删除的记录,就是数据空洞。会浪费空间,如果被标记删除的数据过多也会影响查询效率。
3、优化表(重建表),删除被标识删除的数据
optimize table <table_name>; 或者 alter table <table_name> engine=InnoDB
原理
optimze table 原理。建立一个临时表B,然后把A(存在数据空洞的表)中的数据查询出来,全部重新插入到临时表B中。最后再用临时表B替换表A即可,这就是重建表的过程。
alter table 和 optimize table 区别
alter table t engine=InnoDB (也就是recreate) , 而 optimize table t (等于是recreate + analyze)
4、应该定期优化表 在夜深人静的时候执行 optimize table 命令
5、mysql 命令执行 磁盘数据删除情况
1、drop table table_name 立刻释放磁盘空间 ,不管是 Innodb和MyISAM ;
2、truncate table table_name 立刻释放磁盘空间 ,不管是 Innodb和MyISAM 。truncate table其实有点类似于drop table 然后creat,只不过这个create table 的过程做了优化,比如表结构文件之前已经有了等等。所以速度上应该是接近drop table的速度;
3、delete from table_name删除表的全部数据,对于MyISAM 会立刻释放磁盘空间 (应该是做了特别处理,也比较合理),InnoDB 不会释放磁盘空间;
4、对于delete from table_name where xxx带条件的删除, 不管是innodb还是MyISAM都不会释放磁盘空间;
5、delete操作以后使用optimize table table_name 会立刻释放磁盘空间。不管是innodb还是myisam 。所以要想达到释放磁盘空间的目的,delete以后执行optimize table 操作。
6、delete from表以后虽然未释放磁盘空间,但是下次插入数据的时候,仍然可以使用这部分空间