MySQL表空间是InnoDB引擎组织物理存储的逻辑容器,直接对应磁盘文件(如ibdata1或.ibd),存储数据页、索引页、undo日志、双写缓冲区等二进制块;系统表空间存数据字典和系统段,删表不释放空间;独立表空间(.ibd)支持物理删除,通用表空间需手动DROP TABLESPACE清理。

MySQL表空间到底存什么?
表空间不是目录、不是数据库名,而是InnoDB引擎用来组织物理存储的逻辑容器。它直接对应磁盘上的文件(比如ibdata1或xxx.ibd),里面装的是数据页、索引页、undo日志、双写缓冲区等真实二进制块。
你执行CREATE TABLE时,InnoDB不会直接往磁盘写一行数据,而是先在所属表空间里找空闲页,再把数据序列化填进去。所以表空间大小增长,本质是页被分配出去了,不是“文件变大”这么简单。
- 系统表空间(
ibdata1):默认存在,存数据字典、undo日志、系统段——删表不释放空间 - 独立表空间(
.ibd文件):每个表一个文件,innodb_file_per_table=ON才启用,DROP TABLE会直接删掉整个文件 - 通用表空间(
CREATE TABLESPACE建的):人工创建的共享容器,可跨库放多个表,支持加密、自定义路径、FILE_BLOCK_SIZE
怎么查当前用了哪些表空间?
别翻配置文件,直接查information_schema.FILES最准:
SELECT TABLESPACE_NAME, FILE_NAME, FILE_TYPE, TOTAL_EXTENTS FROM information_schema.FILES WHERE FILE_TYPE = 'DATAFILE';
注意三点:
-
TABLESPACE_NAME为innodb_system的就是系统表空间 - 普通表如果显示
TABLESPACE_NAME和库名一致,说明用了独立表空间(文件在datadir/数据库名/表名.ibd) - 通用表空间的名字是你自己起的,
FILE_NAME可能是绝对路径,比如/ssd/mysql/ts_general.ibd
如果查询为空,大概率是innodb_file_per_table=OFF且没建过通用表空间——所有新表都挤进ibdata1了。
为什么删了表,磁盘空间还不见少?
这是最常踩的坑:只有独立表空间和通用表空间支持物理删除;系统表空间里的表,DROP TABLE只是逻辑标记,ibdata1文件体积纹丝不动。
验证方法:ls -lh /var/lib/mysql/ibdata1 和 du -sh /var/lib/mysql/ibdata1 对比,如果后者远大于前者,说明有大量已删表残留的空间。
- 救急方案:备份+重建实例(停机,导出
mysqldump,删掉整个datadir,重装初始化,再导入) - 长期规避:确认
innodb_file_per_table=ON(5.6+默认开启),新表自动走.ibd,老表可用ALTER TABLE t ENGINE=InnoDB迁移过去 - 通用表空间里删表也不释放空间,得手动
DROP TABLESPACE xxx——但前提是里面真没表了,否则报错ERROR 3137 (HY000)
收缩一个巨大的.ibd文件怎么做?
OPTIMIZE TABLE或ALTER TABLE ... ENGINE=InnoDB能重建表、消除页内碎片,但有个关键前提:该表必须用的是独立表空间(即.ibd存在且innodb_file_per_table=ON)。
实操注意点:
- 在线重建(MySQL 5.6+):默认
ALGORITHM=INPLACE,只锁DML,不影响查询;但若表有全文索引或外键,可能退化为COPY模式 - 显式指定更安全:
ALTER TABLE t ALGORITHM=INPLACE, LOCK=NONE,失败会立刻报错,不盲等 - 别在业务高峰跑——即使online,也会显著增加I/O和CPU压力,观察
SHOW PROCESSLIST里的altering table状态 - 重建后
.ibd变小,但操作系统层面不一定立即回收(ext4延迟分配),可用fstrim或重启MySQL触发
通用表空间无法单表收缩,整个.ibd文件只能靠DROP TABLESPACE彻底删除——所以一开始规划时就得想清楚:哪些表放一起、是否需要长期保留。


















