MySQL 8.0 不支持压缩索引,仅支持 ROW_FORMAT=COMPRESSED 的数据页压缩;所谓“压缩索引”是混淆数据页压缩、KEY_BLOCK_SIZE 参数或新索引特性所致,实测索引页大小保持16KB不变。

MySQL 8.0 **不支持“压缩索引”这一功能**——这是个常见误解。官方文档和所有已知版本(包括 8.0.33 及后续 LTS 版本)中,INDEX 本身不可被压缩;真正可压缩的是 ROW_FORMAT=COMPRESSED 的表数据页,且仅对 InnoDB 存储引擎生效,依赖 innodb_file_per_table=ON 和 innodb_file_format=Barracuda(已弃用但仍隐式启用)。
为什么你搜到的“压缩索引”大多不成立
所谓“压缩索引”,常是混淆了以下三类机制:
- 误把
ROW_FORMAT=COMPRESSED表的 数据页压缩 当成索引压缩(实际 B+ 树索引页仍以常规格式存储,未压缩) - 把
KEY_BLOCK_SIZE参数(仅在ROW_FORMAT=COMPRESSED下生效)当作索引控制项(它只影响数据页,不影响索引页大小) - 将 MySQL 8.0 的
INVISIBLE、DESC或函数索引等新特性误称为“压缩”(它们解决的是可见性、排序效率或表达式查询问题,与空间无关)
实测验证:对一个 10GB 的大表执行 ALTER TABLE t ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; 后,INFORMATION_SCHEMA.INNODB_SYS_INDEXES 中该表所有索引的 page_size 字段值仍为 16384(即 16KB),未变化。
真正能减小 TB 级库物理占用的可行路径
目标不是“压缩索引”,而是降低整体磁盘 footprint。关键在数据页 + 索引协同优化:
-
启用表级压缩:必须满足
innodb_file_per_table=ON(默认开启),再对单表执行ALTER TABLE t ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;(KEY_BLOCK_SIZE可选 1/2/4/8,单位 KB;值越小压缩率越高,但 CPU 开销越大) -
删除冗余索引:运行
SELECT * FROM sys.schema_unused_indexes;找出长期未被优化器使用的索引,DROP INDEX直接释放空间(注意先确认无慢查询依赖) -
用覆盖索引减少回表:把高频查询的
SELECT列全部包含进复合索引,避免读取主键聚簇索引页——间接减少 I/O 和缓存压力,对 SSD 容量感知更明显 -
归档冷数据并分区:对时间字段建
RANGE分区,用ALTER TABLE t DROP PARTITION p_old快速释放冷数据空间(比DELETE节省大量 undo log 和 buffer pool 压力)
KEY_BLOCK_SIZE 设置不当会引发严重问题
这不是调优选项,而是危险开关:
- 若
KEY_BLOCK_SIZE设为 1 或 2,某些长文本字段(如TEXT、VARCHAR(5000))可能触发Row size too large错误,因压缩后仍需保证单页至少存 2 行 - 压缩表在
mysqldump时默认解压导出,备份文件反而更大;需配合--compress-output=LZ4(MySQL 8.0.22+)或外部工具(如zstd)二次压缩 -
KEY_BLOCK_SIZE修改后,INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES的FILE_SIZE字段不会立即更新——要等后台 purge 线程完成页回收,可能延迟数小时
真正节省 TB 级空间的核心动作,从来不是“压缩索引”,而是删掉不用的索引、压缩数据页、归档冷分区、用覆盖索引避免额外读取——这些操作每一步都直接影响磁盘用量,且效果可量化。别被术语带偏,先跑 sys.schema_unused_indexes 和 INFORMATION_SCHEMA.TABLES 看真实占用构成,再动手。


















