查单个表索引大小应直接查询information_schema.tables的index_length字段,它精确反映b+树等索引结构的物理占用字节数,不包含数据,单位为字节。

查单个表的索引大小:直接定位 index_length
MySQL 把每张表的数据大小和索引大小分别记在 information_schema.TABLES 里,index_length 字段就是你要的索引物理占用(单位字节),它不包含数据,只算 B+ 树结构、二级索引页、聚簇索引的非叶子节点等实际写入磁盘的部分。
实操建议:
- 先切到系统库:
USE information_schema; - 查某张表(比如
orders)的索引大小(MB):SELECT table_name, ROUND(index_length / 1024 / 1024, 2) AS 'index_size_mb' FROM TABLES WHERE table_schema = 'your_db' AND table_name = 'orders';
- 注意:如果表是空的或刚建好没插入数据,
index_length可能为 0 —— 这不是 bug,InnoDB 默认不预分配索引页 - 别用
SHOW INDEX,它只告诉你有哪些索引,不报大小
查整个库的索引总用量:聚合 index_length 就行
一个库可能有几十上百张表,手动加太累。直接对 information_schema.TABLES 按库名分组求和,就能看到这个库所有索引加起来占了多少 MB。
实操建议:
- 执行这条 SQL:
SELECT table_schema AS 'db', ROUND(SUM(index_length) / 1024 / 1024, 2) AS 'total_index_mb' FROM TABLES WHERE table_schema = 'your_db' GROUP BY table_schema;
- 如果想顺带看数据大小和总空间,把
SUM(data_length)和SUM(data_length + index_length)一起加上就行 - 别漏掉
WHERE table_schema = 'xxx'—— 否则会扫全实例所有库,慢且不准(尤其跨租户环境)
为什么查出来的大小 ≠ 文件系统里 .ibd 文件大小?
index_length 是 InnoDB 引擎统计的「逻辑已用空间」,而 .ibd 文件是物理文件,两者常有偏差,原因很实在:
- 删除大量数据后,InnoDB 不自动收缩文件,
index_length会下降,但.ibd大小不变 - 执行过
OPTIMIZE TABLE或ALTER TABLE ... FORCE才可能回收空间,但也会锁表、耗 IO - 如果启用了
innodb_file_per_table=OFF,所有表共用ibdata1,那index_length仍准,但你根本看不到单个表对应哪个文件 - 临时表、分区表子分区、全文索引的 FTS cache 都不计入
index_length,它们走的是另一套内存/磁盘管理机制
哪些索引容易“悄悄吃空间”?重点关注这几类
不是所有索引都一样重。有些设计看着合理,一上线就让 index_length 翻倍:
- 字符串字段建了前缀索引但前缀太长,比如
VARCHAR(500)上建INDEX(content(300))—— 每条索引记录存 300 字节,比默认content(191)多占近 60% 空间 - 联合索引顺序不合理,导致无法复用,被迫多建几个索引,比如
(a,b,c)和(a,c)共存,后者大概率冗余 - JSON 字段上建了
GENERATED COLUMN + INDEX,生成列本身要存,索引还要再存一遍,double 花费 - 时间字段用
DATETIME而非TIMESTAMP,前者占 8 字节,后者才 4 字节,索引里每条记录都多 4 字节,千万级表就是额外 40MB+
真正要盯的,从来不是“有没有索引”,而是“这个索引的每字节是不是都换来真实查询收益”。index_length 数值本身没意义,对比 data_length 看占比、结合 Handler_read_next 看命中率,才算摸到门道。











