只有启用独立表空间(innodb_file_per_table=1)时,OPTIMIZE TABLE或ALTER TABLE ... ENGINE=InnoDB才能真正缩小.ibd文件;否则操作仅在共享表空间ibdata1内整理,文件大小不变。

确认表是否在独立表空间里
OPTIMIZE TABLE 或 ALTER TABLE ... ENGINE=InnoDB 能否真正缩小 .ibd 文件,取决于表是否启用独立表空间。如果表还在共享表空间 ibdata1 里,所有“释放空间”操作都只是内部整理,ibdata1 永远不会变小。
先查关键配置:SELECT @@innodb_file_per_table —— 返回 1 才表示独立表空间已启用;再查具体表:SELECT TABLE_NAME, CREATE_OPTIONS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table',看输出里是否含 ROW_FORMAT 或明确列出 FILE_PER_TABLE。
- 若
@@innodb_file_per_table = 0,改配置并重启 MySQL 后,新创建的表才走独立表空间,老表仍留在ibdata1中 - 老表迁移需显式执行
ALTER TABLE your_table ENGINE=InnoDB(前提是已开启innodb_file_per_table),否则只是重建索引,不生成新.ibd - 别信
SHOW CREATE TABLE输出里没提FILE_PER_TABLE就一定不在独立空间——它默认不显示,得靠CREATE_OPTIONS字段判断
TRUNCATE 后 .ibd 文件大小不变怎么办
InnoDB 的 TRUNCATE TABLE 不删文件,只清空页、重置 AUTO_INCREMENT,.ibd 物理大小纹丝不动。这不是 bug,是设计行为。
真正收缩文件必须跟一步重建操作:要么 OPTIMIZE TABLE your_table,要么更明确的 ALTER TABLE your_table ENGINE=InnoDB。二者效果一致,后者语义更清晰、兼容性略好。
-
TRUNCATE是 DDL,不可回滚,且会重置自增 ID —— 如果业务依赖连续 ID,不能直接用 - 如果表太大怕锁太久,别硬扛
OPTIMIZE,改用pt-online-schema-change --alter "ENGINE=InnoDB" --execute在线重建 - 注意临时空间:重建过程会写临时文件,默认走
/tmp,大表容易爆盘;可通过SET SESSION innodb_tmpdir = '/path/to/big/disk'指定位置
DELETE 大量数据后空间不回收的应对方式
DELETE FROM ... WHERE ... 只标记行删除,不归还磁盘空间给操作系统。你看到 DATA_LENGTH 没变、du -sh *.ibd 不降,完全正常。
想真正释放空间,有两个路径:
- 删完立刻执行
OPTIMIZE TABLE(仅对独立表空间有效) - 更稳妥的做法是分批
DELETE+pt-osc替换整表,避免长事务和锁表风险 - 如果目标是清空整表,别用
DELETE再OPTIMIZE—— 它要搬运所有“逻辑已删但物理未清”的记录,比TRUNCATE + OPTIMIZE更慢、更占 IO
检查碎片程度:SELECT DATA_LENGTH, DATA_FREE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'your_table'。若 DATA_FREE / DATA_LENGTH > 0.25,说明碎片严重,优化才有意义;否则纯属浪费资源。
索引体积反超数据本身的排查点
常见于在 VARCHAR(2000) 或 TEXT 字段上建了普通索引。InnoDB 二级索引会把索引列值 + 主键值一起存,一个索引项可能几 KB,索引文件轻松干翻数据文件。
查问题索引:SELECT INDEX_NAME, SEQ_IN_INDEX, COLUMN_NAME, SUB_PART FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table' ORDER BY INDEX_NAME, SEQ_IN_INDEX,重点看 SUB_PART 是否为 NULL(表示全字段索引)以及 COLUMN_NAME 类型是否过长。
- 对长文本字段,优先考虑前缀索引:
INDEX(col_name(100)),而非全字段索引 - 全文检索需求改用
FULLTEXT索引,别用普通 B-tree - 删掉无用索引后,记得跑
ANALYZE TABLE更新统计信息,否则优化器可能继续走错路
真正释放空间的关键不在“删什么”,而在“删完怎么让文件缩回去”——这一步漏掉,磁盘就永远卡在高位。独立表空间、重建动作、临时空间准备,三者缺一不可。


















