InnoDB无“动态/静态行格式”概念,其ROW_FORMAT包括COMPACT、DYNAMIC、COMPRESSED、REDUNDANT四种;DYNAMIC为5.7+默认,支持大字段溢出存储,与MyISAM的动态表机制完全不同。

MySQL 本身没有“动态行格式”和“静态行格式”的全局概念,这是 MyISAM 引擎特有的存储格式分类;InnoDB 完全不使用这套命名体系,它用的是 ROW_FORMAT(如 COMPACT、DYNAMIC、COMPRESSED),二者不能混为一谈。
MyISAM 的静态表 vs 动态表怎么选
MyISAM 表在创建时会根据字段类型自动决定用静态还是动态格式,无法显式指定,但你可以通过字段定义间接控制:
- 静态表:所有列都是固定长度类型(
CHAR、INT、DATE等),且没有NULL允许(或显式声明NOT NULL)——这时 MyISAM 会按最大可能长度分配每行空间 - 动态表:只要包含任意一个可变长字段(
VARCHAR、TEXT、BLOB)或允许NULL,MyISAM 就会启用动态格式,每行额外加 1–2 字节记录长度和 NULL 位图 - 静态表查询快、崩溃后易恢复,但浪费空间(比如
CHAR(100)存 "a" 也占 100 字节);动态表省空间,但频繁UPDATE/DELETE会产生碎片,需定期运行OPTIMIZE TABLE - 注意:
CHAR字段末尾空格会被自动截断,即使你插入'abc ',查出来也是'abc'—— 这是静态表的隐式行为,不是 bug
InnoDB 的 ROW_FORMAT=DYNAMIC 是什么
InnoDB 的 ROW_FORMAT 是建表或修改表时可显式设置的参数,和 MyISAM 的“静态/动态”完全无关。其中 DYNAMIC 是 5.7+ 默认值,关键影响是:
-
DYNAMIC:大字段(VARCHAR、TEXT、BLOB)超出页大小(16KB)时,只在主键索引页存 20 字节指针,实际数据存溢出页(off-page),避免主键页膨胀 -
COMPACT(旧默认):大字段仍尝试存入主键页,容易导致页分裂和性能抖动,尤其当VARCHAR(8000)频繁更新时 - 切换
ROW_FORMAT必须ALTER TABLE ... ROW_FORMAT=DYNAMIC并重建表,不是纯元数据变更 -
SHOW CREATE TABLE里能看到当前ROW_FORMAT,但 MyISAM 表永远不显示这个字段——因为它压根不用
为什么不能把 MyISAM 的“动态表”和 InnoDB 的 ROW_FORMAT=DYNAMIC 当一回事
两者设计目标和实现机制完全不同:
- MyISAM 动态表解决的是“单行长度不确定”,靠在每行开头加长度头;InnoDB
DYNAMIC解决的是“大字段挤占 B+ 树节点”,靠溢出页分离存储 - MyISAM 动态表仍用堆表结构,无事务、无 MVCC;InnoDB
DYNAMIC必须配合聚簇索引、undo log、buffer pool 工作 - 如果你看到某文档说“InnoDB 动态行格式支持行压缩”,那是错的——
ROW_FORMAT=COMPRESSED才负责压缩,且需要KEY_BLOCK_SIZE配合 - 迁移 MyISAM 到 InnoDB 时,别试图“保持动态格式”,直接用
ENGINE=InnoDB ROW_FORMAT=DYNAMIC即可,InnoDB 会按自己的规则重新组织数据
最常被忽略的一点:MyISAM 的静态/动态是创建时自动推导、不可更改的物理布局;而 InnoDB 的 ROW_FORMAT 是可显式配置、可修改的逻辑策略,且修改后必须重建表。混淆这两者,轻则导致误判性能瓶颈,重则在迁移时丢掉大字段的溢出优化能力。


















