必须开启innodb_file_per_table并配置Barracuda文件格式,再将表行格式设为DYNAMIC(而非COMPACT),才能真正优化BLOB/TEXT性能:DYNAMIC使长字段整存溢出页、主页仅留20字节指针,提升页填充率、减少随机I/O和page split。

开启 innodb_file_per_table 是必要前提,但单靠它解决不了 BLOB/TEXT 性能问题;真正起作用的是行格式(ROW_FORMAT)的选择,尤其是 DYNAMIC 与 COMPACT 的差异。
怎么确认当前表是否用了独立表空间和合适行格式
先查配置是否生效:
-
SELECT @@innodb_file_per_table;返回1表示已启用(但只对新建表有效) -
SHOW VARIABLES LIKE 'innodb_file_format';必须是Barracuda(Antelope不支持DYNAMIC)
再查具体表:
SELECT TABLE_NAME, ROW_FORMAT, DATA_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table';
如果 ROW_FORMAT 是 COMPACT 或 REDUNDANT,且表里有 TEXT/BLOB,基本可以确定长字段被截前 768 字节存主页、其余进溢出页——这是随机 I/O 和空间浪费的根源。
为什么 DYNAMIC 比 COMPACT 更适合大字段
COMPACT 在 Antelope 文件格式下,对任何超过 768 字节的 TEXT/BLOB 都强制截断并分页存储,哪怕只多 1 字节;而 DYNAMIC(需 Barracuda)默认把整段长内容移出主页,主记录只留 20 字节指针。
- 主数据页更紧凑,填充率更高,减少 page split
- 避免因溢出页分散导致的额外随机读(尤其在
SELECT *场景) - 删除大字段值时,
DYNAMIC能更快释放溢出页空间(COMPACT的溢出页回收更滞后)
注意:DYNAMIC 不等于压缩,也不降低 CPU 开销;它只是改变了长字段的物理存放策略。
如何安全地把旧表切换到 DYNAMIC 行格式
不能只改配置文件,必须对已有表执行 ALTER TABLE:
ALTER TABLE your_table ROW_FORMAT = DYNAMIC, ENGINE = InnoDB;
这个操作会重建表,期间锁表(Online DDL 在 MySQL 5.6+ 对部分 ALTER 支持并发 DML,但 ROW_FORMAT 变更仍需 copy algorithm,建议低峰期执行)。
- 执行后检查:
SHOW CREATE TABLE your_table;确认输出含ROW_FORMAT=DYNAMIC - 验证磁盘效果:
ls -lh /var/lib/mysql/your_db/your_table.ibd,大小变化不一定明显,但后续写入的长字段不会再污染主数据页 - 如果表很大,考虑先用
mysqldump --no-create-info导出数据,DROP后重建带ROW_FORMAT=DYNAMIC的表再导入
容易被忽略的兼容性陷阱
innodb_file_per_table 开启后,删表确实会删掉 .ibd 文件,但 ibdata1 里的元数据、undo log、change buffer 等仍存在,不会自动收缩——这和你能不能看到 .ibd 文件无关。
-
innodb_file_format = Barracuda必须写进my.cnf的[mysqld]段并重启才永久生效(MySQL 5.7+ 支持动态设置,但某些版本重启后仍可能回退) - 即使开了
innodb_file_per_table和Barracuda,建表时不显式指定ROW_FORMAT=DYNAMIC,MySQL 5.7+ 默认用DYNAMIC,但 5.6 默认仍是COMPACT -
COMPRESSED行格式虽然省空间,但会显著拖慢INSERT/UPDATE(TPS 下降约 90%),除非你明确做了 I/O 压力测试,否则别开
真正影响大字段性能的,从来不是“有没有 .ibd 文件”,而是“长内容到底存哪儿、怎么取”。DYNAMIC 把问题从“主页塞不下”变成“指针跳一次”,这是可量化的改善点。











