InnoDB表磁盘占用通常大于MyISAM,根本原因在于其聚簇索引强制数据与主键索引耦合于同一B+树页中,最小存储单元为16KB页且需初始化完整结构,而MyISAM按需分配、可从几KB起步;DELETE不释放空间是因仅标记删除供复用,非真正截断文件。

InnoDB 表磁盘占用通常比 MyISAM 大,根本原因不在“多存了日志”或“字段压缩差”,而在于聚簇索引强制将数据和主键索引耦合在同一个 B+ 树页中,导致空间无法被 MyISAM 那样灵活复用。
为什么 CREATE TABLE ... ENGINE=InnoDB 一建就比 MyISAM 占更多空间
新建空表时,InnoDB 就会为每个表分配至少一个 16KB 的 .ibd 文件(即使只有一行),因为它的最小存储单元是页(page),且必须初始化聚簇索引树结构;MyISAM 的 .MYD 和 .MYI 文件则可从几 KB 起步,按需增长。
- MyISAM 空表:.frm(表定义)+ .MYD(0 字节)+ .MYI(仅根节点,极小)
- InnoDB 空表:.frm + .ibd(默认 16KB,含 page header、infimum/supremum 记录、空闲空间链表等)
- 如果
innodb_file_per_table=OFF,所有表共用ibdata1,初始就可能几百 MB,且永不收缩
删除数据后 du -sh 看不到空间释放,不是 bug 是设计
InnoDB 的 DELETE 只是把记录标记为“已删除”,并加入 purge 队列;页内空闲空间保留在该页中供后续 INSERT 复用,但不会合并释放回文件系统——这和 MyISAM 直接截断 .MYD 文件的行为完全不同。
- 执行
DELETE FROM t WHERE id > 1000后,ls -lh t.ibd和du -sh均无变化 -
OPTIMIZE TABLE t或ALTER TABLE t ENGINE=InnoDB才会重建表、丢弃空洞、真正缩小 .ibd - 注意:
OPTIMIZE TABLE在innodb_file_per_table=OFF下无效,对共享表空间不起作用
CHAR(120) 字段让 InnoDB 反而更省空间?那是特例,别当通则
确实存在 InnoDB 比 MyISAM 小的案例,比如全 CHAR 字段且大量为空值——InnoDB 对 CHAR 中的尾部空格不实际存储(尤其 ROW_FORMAT=DYNAMIC),而 MyISAM 在 FIXED 行格式下会为每个 CHAR(120) 分配满 120 字节,不管是否为空。
- 这个优势只在特定字段类型 + 特定行格式 + 高比例空值时出现
- 一旦改用
VARCHAR或填充非空内容,MyISAM 立刻反超(因索引压缩 + 数据分离) - 真实业务中,这种“InnoDB 更小”的场景极少,且不可靠,不能作为选型依据
真正影响空间的关键配置:别只盯 ROW_FORMAT
很多人调 ROW_FORMAT=COMPRESSED 或 KEY_BLOCK_SIZE,但更关键的是底层组织逻辑是否允许紧凑存放——而这由聚簇索引决定。
-
innodb_file_per_table=ON是前提:否则所有表挤在ibdata1,删表也不释放空间 -
innodb_page_size默认 16KB,哪怕只存一行,也占一页;MyISAM 的 .MYD 没这种硬约束 - 辅助索引叶子节点存的是主键值,不是行地址——这意味着主键越长(如
BIGINT+ 复合主键),每个二级索引条目就越大,空间放大效应越明显
聚簇索引带来的空间开销不是缺陷,而是为事务、MVCC、崩溃恢复和并发锁服务的代价。想压低磁盘占用,与其纠结单表大小,不如审视是否真需要 InnoDB 提供的那些能力;若只是静态报表库,MyISAM 的轻量结构反而更合适——但得清楚放弃的是什么。


















