
大家是否遇到过这种情况,一张表占2个G,想着都是无用数据,把数据删除,释放些空间,然后一顿操作,运行Sql一看,我去!为啥空间还占2个G?不管遇到没遇到,想更深入了解下,就继续往下看吧!
查看数据库容量大小
selecttable_schema as '数据库',table_name as '表名',table_rows as '记录数',truncate(data_length/1024/1024, 2) as '数据容量(MB)',truncate(index_length/1024/1024, 2) as '索引容量(MB)'from information_schema.tablesorder by data_length desc, index_length desc;
查看所有数据库各表容量大小
selecttable_schema as '数据库',table_name as '表名',table_rows as '记录数',truncate(data_length/1024/1024, 2) as '数据容量(MB)',truncate(index_length/1024/1024, 2) as '索引容量(MB)'from information_schema.tablesorder by data_length desc, index_length desc;
要查看单个自己根据需要添加相应Where条件即可。
要想搞清楚数据为何不释放,就要先来了解下数据是如何存放的。在Innodb中,我们都知道页是Mysql管理数据的最小单元,页的默认大小是16K。
Innodb 逻辑存储结构,从上往下依次为:Tablespace、Segment、Extent、Page 以及 Row。

Innodb中页的类型有很多,如数据页(B-tree Node)、undo页(undo Log Page)、系统页 (System Page)等,这里我们主要来了解数据页。

在数据页中,User Records是以我们指定的行格式进行存储的,每当插入一条数据,都会从Free Space中申请一定的空间划分到User Records区域,如果Free Space空间耗尽,就要去申请新的页了。
我们通过上节,已经了解了页的相关结构,以及新插入数据,是如何申请空间进行存储的,那本节就要了解下进入的数据行在User Rcords中又是如何存放的。
我们通过上节,已经了解了页的相关结构,以及新插入数据,是如何申请空间进行存储的,那本节就要了解下进入的数据行在User Rcords中又是如何存放的。
阅读过上篇文章(Mysql-一行能存多少数据?)的应该知道Mysql中数据是以指定的行格式储存在页中的,Mysql的默认行格式的DYNAMIC。DYNAMIC的行格式主要包含记录头、可变字段长度列表、空值列表、字段值列表。
在Mysql记录头中主要包含以下结构:
| delete_mask | 标记是否被删除 |
| min_rec_mask | 树的每层非叶子节点的最小记录标识 |
| n_owned | 当前记录拥有的记录数 |
| heap_no | 当前记录在页面堆的位置 |
| record_type | 记录类型,如最大、最小、叶子等 |
| next_record | 下一条记录的位置 |
注意到了吗,这里有一个删除标识,占用1个二进制位,0表示未删、1已删除。在Mysql要删除一条数据时,Mysql只是先对其打上一个标签,因为物理删除实在太耗时了,那空间这这么白白浪费了吗?其实并不是,这些被删除的数据会在Mysql中组成一个垃圾处理链(是不是有点像Java垃圾处理中的标记清除法),被标记成删除的数据所占的空间都是可以重复使用的,后续如果有新插入的数据,会对这一部分空间进行重复使用。
释放被删除数据的空间很简单使用optimize,对表进行空间整理,使用方式如下:
optimize table t_user
请谨慎使用此命令,因为此命令的本质在于alter table,会造成锁表。
如果必须要对空间整理推荐使用pt-online-schema-change进行处理,具体使用方式自行百度。




