InnoDB不支持前缀压缩索引,仅MyISAM支持;InnoDB的前缀索引只是截取字符存入B+树,不压缩页,真正减少磁盘占用需启用ROW_FORMAT=COMPRESSED与KEY_BLOCK_SIZE。

innodb 引擎本身不支持前缀压缩索引——这是 MyISAM 的特性,InnoDB 对字符串列建前缀索引时,只是截取前 N 个字符/字节存入 B+ 树,不会对索引页做字典压缩或前缀压缩编码。
想在 InnoDB 中真正减少索引(及数据)的磁盘占用,得用它的原生压缩机制,而不是依赖“前缀索引”来“压缩”。
innodb_file_per_table 和 ROW_FORMAT=COMPRESSED 是前提
InnoDB 表压缩不是靠索引定义控制的,而是通过表级存储格式启用:
- 必须开启
innodb_file_per_table = ON(默认已开,但需确认) - 表必须使用
ROW_FORMAT=COMPRESSED或ROW_FORMAT=DYNAMIC(后者支持压缩但需配合KEY_BLOCK_SIZE) - 压缩实际生效依赖
KEY_BLOCK_SIZE参数(如KEY_BLOCK_SIZE=4表示压缩后页大小为 4KB)
ALTER TABLE users ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4;
注意:
KEY_BLOCK_SIZE值必须是 1、2、4、8 或 16,且不能大于innodb_page_size(默认 16KB)。压缩页会在写入磁盘前被 zlib 压缩,读取时自动解压。
前缀索引 ≠ 压缩索引:它只省空间,不省 I/O 开销
你加 INDEX(city(7)),确实让索引键变短、B+ 树层级更浅、内存中缓存更多节点,但它:
- 不减少物理页数量(索引页仍是 16KB,默认未压缩)
- 不降低磁盘读写量(除非配合
ROW_FORMAT=COMPRESSED) - 无法用于
ORDER BY、GROUP BY、覆盖索引(因为缺失后缀内容) - 选择性下降:比如
email(10)可能大量重复,导致查询仍要回表甚至全索引扫描
所以,如果目标是“减少磁盘空间”,优先考虑表压缩;如果目标是“让长文本列上的索引更快更小”,再评估前缀长度是否合理。
如何验证前缀索引是否真节省了空间?
别猜,查 information_schema.INNODB_SYS_INDEXES 和 INNODB_SYS_TABLES:
SELECT t.NAME AS table_name, i.NAME AS index_name, i.SEQUENCE_NUM, i.PAGE_NO, i.INDEX_ID FROM information_schema.INNODB_SYS_INDEXES i JOIN information_schema.INNODB_SYS_TABLES t ON i.TABLE_ID = t.TABLE_ID WHERE t.NAME LIKE 'your_db/your_table';
再结合 SHOW INDEX FROM your_table 看 Sub_part 列——非 NULL 表示用了前缀索引,但这个值不反映磁盘节省量。
真实空间变化得看 du -h 表空间文件(如 your_table.ibd),或者用 SELECT data_length, index_length FROM information_schema.TABLES 对比压缩前后。
前缀索引和表压缩解决的是不同层面的问题:前者是“逻辑键裁剪”,后者是“物理页压缩”。容易混淆的点在于——MyISAM 的前缀压缩(prefix compression)是引擎内置的页级优化,而 InnoDB 把这事交给了 KEY_BLOCK_SIZE + zlib,跟前缀索引完全无关。


















