COMPACT与DYNAMIC的核心区别在于大字段溢出管理:COMPACT保留前768字节内联+溢出,DYNAMIC则整段移出主记录页、仅存20字节指针,从而解耦大字段更新与聚簇索引稳定性。

COMPACT 和 DYNAMIC 的核心区别不在“是否紧凑”,而在溢出数据如何管理
DYNAMIC 不是 COMPACT 的“更紧凑版本”,而是对大字段(BLOB、TEXT、长 VARCHAR)生命周期与索引稳定性的重新建模。关键分歧点在于:当一行中某个可变长度列超过页内空间限制时,COMPACT 仍强制在聚簇索引记录里保留前 768 字节,而 DYNAMIC 直接把整段数据移出主记录页,只留一个 20 字节的溢出页指针。
-
COMPACT:B+ 树节点里混存“部分大字段 + 指针”,更新该字段可能触发页分裂(即使只改最后几个字节) -
DYNAMIC:B+ 树节点只存指针,主键索引结构几乎不受大字段内容变更影响 - MySQL 5.7+ 默认用
DYNAMIC,不是因为“更省空间”,而是为降低索引维护成本
为什么 ALTER TABLE ROW_FORMAT=DYNAMIC 后,EXPLAIN 显示的 rows 估算没变
行格式切换不改变统计信息,也不自动触发 ANALYZE TABLE。优化器看到的行数、平均行长等元数据仍基于旧格式估算,尤其当表里有大量 TEXT 字段时,COMPACT 下的统计值会高估实际主记录体积。
- 必须手动执行
ANALYZE TABLE table_name才能让优化器感知新布局 -
INFORMATION_SCHEMA.TABLES中的AVG_ROW_LENGTH字段在切换后不会立即更新 - 对于含
JSON或长VARCHAR的表,DYNAMIC下真实主记录大小可能比COMPACT小 30%~70%,但不重采样就看不到
COMPACT 表迁移到 DYNAMIC 时容易踩的坑
迁移本身是轻量 DDL(MySQL 5.7+ 支持 ALGORITHM=INSTANT),但语义变化可能引发隐性问题:
- 应用层假设“
SELECT *返回的 TEXT 字段一定在第一次网络包里”——DYNAMIC下它可能被延迟加载(取决于客户端驱动和网络缓冲) - 备份工具(如
mysqldump)若依赖INFORMATION_SCHEMA.COLUMNS的CHARACTER_MAXIMUM_LENGTH做截断判断,可能误判字段实际存储位置 -
innodb_file_per_table=OFF时,DYNAMIC表的溢出页仍写入系统表空间(ibdata1),无法通过TRUNCATE回收空间 -
COMPACT表启用innodb_large_prefix=ON后创建的索引,在DYNAMIC下依然有效,但反向不成立(DYNAMIC表禁用该选项后,已有长索引不会失效,只是新建受限)
什么时候必须用 DYNAMIC,而不是“能用 COMPACT 就凑合”
本质是看业务是否频繁更新大字段,且对主键索引稳定性敏感:
- 表中存在
JSON列并经常JSON_SET()修改局部字段 → 选DYNAMIC,避免每次修改都重写整条聚簇记录 - 使用
pt-online-schema-change迁移大表时,DYNAMIC可显著减少复制延迟(因主记录更小、锁粒度更细) - 表有高频
UPDATE ... WHERE pk = ?且 SET 子句含长VARCHAR→DYNAMIC减少页分裂概率 - 用
innodb_page_size=4k的实例(如某些云托管 MySQL),COMPACT的 768 字节内联阈值极易被突破,DYNAMIC成事实刚需
真正难察觉的点是:行格式一旦设为 DYNAMIC,后续即使删掉所有大字段,InnoDB 也不会自动退回到 COMPACT 的存储逻辑——它已按新契约组织页目录和溢出链,这个契约不可逆。


















