InnoDB空表占16KB是因为以页为最小存储单元,需初始化B+树根节点等结构;MyISAM按需分配,空表几乎不占空间。

为什么InnoDB空表就占16KB而MyISAM几乎不占空间
InnoDB新建空表立刻生成一个16KB的t.ibd文件,这不是配置错误,是它以页(page)为最小存储单元的设计使然——哪怕只建CREATE TABLE t (id INT PRIMARY KEY) ENGINE=InnoDB,也必须初始化B+树根节点、infimum/supremum记录、页头和空闲空间链表等结构。
MyISAM则按需分配:t.frm存表结构(几KB),t.MYD初始为空(0字节),t.MYI仅存索引根节点(通常几百字节)。三者加起来可能不到2KB。
-
innodb_file_per_table=OFF时,所有表挤在ibdata1里,初始就几百MB且永不收缩,此时连“空表占多大”都无从谈起 - MyISAM的
.MYD和.MYI可分别放在不同磁盘路径,但InnoDB的.ibd是单文件封装,无法拆分
DELETE后磁盘空间不释放,到底谁在“假装删了”
InnoDB执行DELETE FROM t WHERE id > 1000后,du -sh t.ibd几乎不变,这不是MySQL卡住,而是它只把记录标记为“可复用”,并加入purge队列;页内空闲空间保留在原页中供后续INSERT复用,但不会合并释放回文件系统。
MyISAM在整表删除(DELETE FROM t)时会真正截断.MYD文件;带WHERE条件的删除虽留空洞,但OPTIMIZE TABLE能较干脆地重写压缩。
- InnoDB要真正收缩文件,必须触发重建:
ALTER TABLE t ENGINE=InnoDB或OPTIMIZE TABLE t -
OPTIMIZE TABLE在innodb_file_per_table=OFF下完全无效——你只是在给ibdata1做无用功 - MyISAM的
myisamchk -r -q能彻底修复碎片,但要求MySQL完全停服,不能在线运行
查真实磁盘占用,别信information_schema.TABLES
SELECT data_length + index_length FROM information_schema.TABLES返回的是逻辑数据量,不含页管理开销、未回收碎片、文件系统块对齐(如4KB对齐导致1KB记录实际占4KB)等。它容易高估MyISAM、严重低估InnoDB的真实压力。
查InnoDB真实物理大小,优先看:du -sh /var/lib/mysql/db_name/t.ibd(前提是innodb_file_per_table=ON);查MyISAM则直接du -sh t.frm t.MYD t.MYI求和即可。
- 若
innodb_file_per_table=OFF,所有表挤在ibdata1里,你根本无法从文件系统区分哪部分属于哪张表 -
SHOW TABLE STATUS LIKE 't'\G里的Data_free字段才是关键指标,>100MB就值得处理 - 碎片率计算应走:
SELECT table_name, ROUND(data_free / (data_length + index_length), 4) AS frag_ratio FROM INFORMATION_SCHEMA.TABLES WHERE engine='InnoDB' AND data_free > 100*1024*1024
字段长度声明对空间影响,InnoDB和MyISAM完全不同
VARCHAR(255)在InnoDB中存"abc"和VARCHAR(100)一样只占3+1字节(内容+长度头),但有两个隐藏代价:一是若字段可能超255字节,InnoDB强制用2字节长度头;二是排序/临时表预估内存时,按定义长度算,VARCHAR(255)更容易触发磁盘临时表。
MyISAM则相反:VARCHAR(255)存"a"就在.MYD里占255+1字节,VARCHAR(100)只占100+1字节——它对定义长度极其敏感,浪费呈线性放大。
- MyISAM已不推荐新项目使用,但维护旧系统时务必收缩冗余
VARCHAR长度,ALTER TABLE MODIFY COLUMN能直接减小.MYD -
TEXT在InnoDB中短于40字节会内联进主页,否则存溢出页;MyISAM一律存在.MYD末尾单独区域,主记录只存偏移量 -
ROW_FORMAT或KEY_BLOCK_SIZE这类参数对空间影响远不如底层聚簇索引机制本身


















