mysql 8.0 默认行格式为 dynamic,但需据字段类型、读写模式等选型;大字段(text/blob/varchar超长)必须用 dynamic 以避免页碎片;compressed 可压缩整页但牺牲性能;compact 仅适用于无大字段且低版本场景。

MySQL 8.0 默认用 DYNAMIC,但“默认”不等于“最合适”——选错行格式可能让大字段查询变慢、页分裂变多、甚至触发 ERROR 1118 (42000): Row size too large。关键得看你的字段类型、读写模式和是否启用压缩。
查清当前表的行格式和真实存储压力
别只信 SHOW CREATE TABLE,它可能掩盖实际物理结构。先确认:
-
SHOW TABLE STATUS LIKE 'your_table'查Row_format和Data_length,注意后者是估算值 - 更准的是查
INFORMATION_SCHEMA.INNODB_TABLES:SELECT NAME, ROW_FORMAT, FILE_SIZE, ALLOCATED_SIZE FROM INFORMATION_SCHEMA.INNODB_TABLES WHERE NAME LIKE '%your_table%'; - 如果表里有大量
VARCHAR(5000)、TEXT或BLOB,且平均长度 > 255 字节,COMPACT很可能已在内部把前 768 字节硬塞进主页,造成页碎片和缓存浪费
大字段(BLOB/TEXT/VARCHAR 超长)必须用 DYNAMIC
DYNAMIC 是唯一对溢出数据做“纯指针+独立溢出页”管理的格式。一旦字段内容超过页内可容纳空间(约 768–1024 字节),COMPACT 和 REDUNDANT 会截断并把前缀存主页,后续访问仍要回溯溢出页;而 DYNAMIC 主页只存 20 字节指针,真正数据全在溢出页链表中,避免主 B+ 树节点膨胀。
- 适用场景:
article.content TEXT、log.payload JSON、用户上传的 base64 图片字段 - 注意:
DYNAMIC不压缩数据,也不减少磁盘占用,但它让主索引页更“干净”,提升范围扫描和排序性能 - MySQL 5.7+ 才完整支持;5.6 只能设但行为不一致,慎用
需要节省磁盘空间且 IO 密集?考虑 COMPRESSED
COMPRESSED 行格式必须搭配 KEY_BLOCK_SIZE 使用(如 KEY_BLOCK_SIZE=4),它会对整个数据页(16KB)做 zlib 压缩,不是单行压缩。效果取决于数据重复率和字符集——utf8mb4 中英文混排压缩率通常只有 20%~40%,但纯日志或报表类文本可达 60%+
- 必须启用
innodb_file_per_table=ON,否则建表直接报错 - 写入性能下降约 10%~25%,因每次刷脏页都要压缩;读取时需解压整页,随机点查延迟略升
- 不能用于系统表空间,也不能和
ENCRYPTION='Y'同时用(会冲突) - 示例语句:
CREATE TABLE t1 (...) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
什么情况下还该用 COMPACT?
仅当满足全部以下条件时才值得保留 COMPACT:
- MySQL 版本 ≤ 5.6,或业务强依赖老备份工具(部分工具不识别
DYNAMIC的溢出页结构) - 表中无任何
TEXT/BLOB,且所有VARCHAR都 ≤ 255 字符(比如全是短标签、状态码、ID) - QPS 极高、对单行读写延迟极其敏感,且已通过监控确认缓冲池命中率 > 99.5%,说明页内紧凑性确实带来了收益
- 不要为兼容性而迁就——MySQL 8.0 已彻底弃用
REDUNDANT,COMPACT也仅作为过渡选项存在
真正容易被忽略的点是:行格式变更(ALTER TABLE ... ROW_FORMAT=...)会触发全表重建,锁表时间与数据量正相关;若表超 10GB,务必在低峰期操作,并提前检查 innodb_online_alter_log_max_size 是否足够。另外,DYNAMIC 表在开启 innodb_strict_mode=ON 时,对超长索引前缀更敏感——CREATE INDEX ON t(col) USING BTREE 若 col 是 VARCHAR(3000),可能直接失败,需显式加 KEY_BLOCK_SIZE 或改用前缀索引。











