information_schema.tables统计不准,因myisam字段反映真实文件大小,而innodb的data_length/index_length仅为估算值,受共享表空间、页分配、碎片及压缩等因素影响,且不包含redo/undo日志与临时空间。

直接评估会严重低估,必须按物理文件 + 日志 + 临时空间三块分别算,不能只看 data_length + index_length。
为什么 information_schema.tables 的统计值不准
MyISAM 表的 data_length 和 index_length 是真实占用(.MYD/.MYI 文件大小),但 InnoDB 的对应字段在 innodb_file_per_table=OFF 时完全无效——所有表挤在 ibdata1 里,data_length 只是估算值。即使开启 innodb_file_per_table=ON,新建空表也会立即分配一个 16KB 的 .ibd 文件,而 MyISAM 同样结构的空表可能只有几 KB。
实操建议:
- 查 MyISAM 原始空间:用
ls -lh /var/lib/mysql/db_name/table_name.{MYD,MYI}看真实文件大小 - 查 InnoDB 预估空间:新建同结构空表后执行
ls -lh /var/lib/mysql/db_name/table_name.ibd,确认是否为 16KB 起步 - 别信
table_rows × avg_row_length,InnoDB 的页内碎片、填充因子、二级索引冗余(尤其含TEXT字段)会让实际占用翻倍
真正要预留的磁盘空间有哪些
迁移不是“换引擎”那么简单,而是全量重建过程。MySQL 强制走 COPY 算法,期间需同时存下旧文件、新 .ibd、redo log 增长、undo log 扩容、以及排序/临时表空间。
必须检查以下几项:
-
df -h /var/lib/mysql—— 主分区剩余空间 ≥ 原.MYD + .MYI总和 × 2.2(SSD 上可压到 × 1.8,HDD 建议 × 2.5) -
du -sh /var/lib/mysql/ib_logfile*—— redo log 默认 48MB,大表迁移中可能临时增长至 200MB+,尤其innodb_log_file_size小于 256MB 时 -
SELECT SUM(data_length + index_length) FROM information_schema.tables WHERE engine = 'MyISAM'—— 这是迁移前所有待转表的总基线,不是单表 - 如果开了
tmpdir在独立磁盘,检查该路径空间;否则/tmp或/var/tmp也可能被写爆(GROUP BY/ORDER BY触发)
迁移后空间不释放是正常现象,别误判为“膨胀”
InnoDB 的 DELETE 不释放磁盘空间,OPTIMIZE TABLE 或 ALTER TABLE ... ENGINE=InnoDB 才能重建并丢弃空洞。所以迁移完立刻 ls -lh table_name.ibd 发现比原 .MYD 大很多,不是出错,是设计如此。
常见误操作:
- 执行完
ALTER TABLE t ENGINE=InnoDB就删掉原.MYD/.MYI—— 错!必须等新表验证一致后再删,且.ibd文件不会自动收缩 - 看到
data_free > 0就以为能回收 —— 错!data_free是页内未用空间,不等于可还给文件系统 - 用
mysqldump导出再导入来“省空间” —— 错!文本格式体积通常比原始.ibd大 30%–50%,且重建过程仍需双倍空间
最易被忽略的是:迁移后若没调大 innodb_buffer_pool_size,大量数据只能从磁盘读,性能反而比 MyISAM 还差——空间涨了,性能却跌了,这不是存储问题,是内存配置没跟上。











