Note
存储引擎
记录 MySQL 存储引擎的作用、常见类型、InnoDB 存储结构与选型原则
存储引擎
存储引擎是 MySQL 中负责组织和访问表数据的组件。SQL 经过解析和优化后,服务层会通过统一接口调用具体的存储引擎,由存储引擎完成数据与索引的读取、写入和空间管理;事务、锁、外键、崩溃恢复等能力也与所选引擎密切相关。
存储引擎的选择以表为单位,而不是以数据库为单位。同一个数据库可以包含使用不同存储引擎的表,数据库或服务器配置的默认引擎只决定建表时没有显式指定引擎的默认选择。
MySQL 体系结构
为了理解存储引擎的位置,可以将 MySQL 的处理过程概括为连接层、服务层、存储引擎层和底层存储四个部分。这是一种便于学习的逻辑划分,不表示各部分在源码中一定具有完全对应的物理边界。
连接层
连接层接收客户端连接,建立和维护会话,并处理身份认证、连接数量及连接资源等问题。权限检查会贯穿语句的处理过程,客户端只有通过相应检查后才能访问数据库对象。
服务层
服务层提供大多数与存储引擎无关的通用能力,包括 SQL 解析、语义与权限检查、查询优化和语句执行等。优化器选择执行计划后,执行器会根据计划调用存储引擎提供的接口,而不直接操作底层数据文件。
存储引擎层
存储引擎层采用可插拔设计。不同引擎通过统一接口与服务层协作,但可以使用不同的数据组织方式、索引结构、锁策略和持久化机制,因此同一条 SQL 在不同引擎上可能具有不同的能力边界与性能特征。
底层存储
存储引擎通过内存缓冲区、表空间、数据文件和日志等结构管理数据,最终由操作系统文件系统和存储设备完成持久化。并非所有引擎都会同时使用这些结构,例如 MEMORY 引擎的表数据主要位于内存中。
一条语句的调用过程
一条访问表数据的语句通常经历以下过程:
- 客户端建立连接并通过身份认证。
- 服务层解析 SQL、检查对象与权限,并由优化器生成执行计划。
- 执行器按照计划,通过存储引擎接口请求记录或提交数据变更。
- 存储引擎访问索引、内存页、数据文件或日志,并将结果返回服务层。
- 服务层整理执行结果并返回客户端。
存储引擎的管理
引擎的作用范围
每张表都有自己的存储引擎。省略建表语句中的 ENGINE 选项时,MySQL 使用 default_storage_engine 指定的默认引擎;MySQL 8.x 的默认引擎是 InnoDB。
同一数据库虽然可以混用引擎,但需要特别注意能力差异。例如,一个事务同时修改 InnoDB 表和 MyISAM 表时,回滚只能撤销支持事务的部分,容易造成业务数据不一致。
常用管理入口
| 入口 | 作用 |
|---|---|
SHOW ENGINES |
查看当前 MySQL 实例可用的存储引擎、默认引擎及其基础能力 |
SHOW TABLE STATUS |
查看表的引擎、行数估计、数据大小等状态信息 |
information_schema.TABLES |
批量查询表与存储引擎等元数据 |
ENGINE = 引擎名 |
在创建表时指定存储引擎 |
ALTER TABLE ... ENGINE = 引擎名 |
转换已有表的存储引擎,通常会重建表并受到目标引擎能力限制 |
default_storage_engine |
设置会话或服务器级的默认存储引擎 |
转换已有表之前,应检查事务、外键、索引和字段类型是否被目标引擎支持,并评估重建表带来的锁、磁盘空间和执行时间成本。
InnoDB
InnoDB 是兼顾可靠性、并发能力和通用性能的事务型存储引擎,也是 MySQL 8.x 的默认存储引擎,适合绝大多数需要持久化的业务表。
核心能力
- 事务与崩溃恢复:DML 操作遵循 ACID 模型,支持提交、回滚,并通过 redo、undo 等机制参与故障恢复和事务一致性维护。
- 并发控制:支持行级锁与多版本并发控制(MVCC)。具体锁定的是记录、间隙还是范围,取决于语句类型、索引、查询条件和隔离级别,不能简单理解为每次操作只锁住一行。
- 索引组织:表数据按聚簇索引组织。聚簇索引的叶子节点保存完整行记录,普通二级索引的叶子节点通常保存索引列和主键值。
- 数据完整性:支持外键约束,可以在写入、更新和删除时维护表之间的引用关系。
- 缓存机制:缓冲池缓存经常访问的数据页和索引页,减少直接访问磁盘的次数。
逻辑存储结构
理解 InnoDB 的空间管理时,可以从表空间逐层观察到记录:
表空间
表空间是 InnoDB 管理数据文件的逻辑容器,可以包含数据页、索引页和相关元数据。常见类型包括系统表空间、独立表空间、通用表空间、撤销表空间和临时表空间。
MySQL 8.x 默认启用独立表空间模式,一张普通 InnoDB 表的数据和索引通常存放在对应的 .ibd 文件中。表也可以按配置或用途放入系统表空间、通用表空间等其他位置,因此不能把“一张表一定对应一个 .ibd 文件”视为绝对规则。
段
段是表空间内特定对象使用的一组页面和区。例如,一个 InnoDB 索引通常分别使用叶子节点段和非叶子节点段。段增长初期可以逐页分配,达到一定规模后再按区分配空间。
区
区是一组连续的页,用于提高批量分配空间的效率。使用默认 16 KiB 页时,一个区为 1 MiB,包含 64 个连续页;如果实例采用其他页大小,区的大小和页数关系也会相应变化。
页
页是 InnoDB 在磁盘和内存之间进行读写与缓存管理的基本单位。默认页大小为 16 KiB,并由实例初始化时的 innodb_page_size 决定,不能把 16 KiB 当作所有实例都不可改变的固定值。
页具有不同用途,例如保存索引记录、undo 信息或空间管理信息。业务行通常以索引记录的形式存放在聚簇索引的数据页中,而不是直接散落在表空间文件里。
行记录
行记录保存业务字段,并可能包含 InnoDB 为事务和版本管理维护的隐藏信息。单行能保存多少数据还受到行格式、页大小和可变长度字段是否使用页外存储等因素影响。
文件与日志
InnoDB 的数据不只涉及表对应的 .ibd 文件,还可能涉及系统表空间、undo 表空间、临时表空间和 redo 日志等。MySQL 8.x 已使用事务型数据字典取代旧版 .frm 元数据文件;InnoDB 的序列化字典信息(SDI)保存在表空间文件内部,而不是为每张 InnoDB 表单独创建 .sdi 文件。
这些文件彼此存在一致性关系,不应在 MySQL 运行期间通过文件系统直接复制、修改或删除来代替数据库提供的备份、恢复和表空间管理机制。
MyISAM
MyISAM 是 MySQL 早期常用的非事务型磁盘存储引擎。它仍可用于兼容旧系统或满足少数明确的特殊需求,但不再是新建通用业务表的优先选择。
核心特点
- 不支持事务、回滚和 MVCC,发生故障时不具备 InnoDB 同等级别的崩溃恢复能力。
- 使用表级锁,写操作会限制同一张表上的并发访问,不适合更新频繁或并发写入较多的业务。
- 不支持外键约束,但支持 B-tree、全文和空间索引等能力。
- 某些只读或以顺序读取为主的特定工作负载可能表现良好,但“读多写少”本身不足以证明 MyISAM 优于 InnoDB,应以真实数据和并发模型下的测试结果为准。
文件组织
每张 MyISAM 表使用 .MYD 文件保存数据,使用 .MYI 文件保存索引。表定义由 MySQL 数据字典管理;对于 MyISAM 等非 InnoDB 引擎,序列化字典信息还会存放在表所在数据库目录的 .sdi 文件中。
MEMORY
MEMORY 引擎将表数据存放在服务器内存中,适合体量可控、可以丢失且需要低延迟访问的临时工作数据或只读缓存。表定义会保留,但 MySQL 服务停止、重启或异常退出后,表中的数据会丢失。
核心特点
- 不支持事务、外键和 MVCC,并使用表级锁,并发写入能力有限。
- 默认使用 Hash 索引,也支持 B-tree 索引。Hash 索引适合等值查找,B-tree 索引可以支持范围访问和有序访问。
- 表容量受
max_heap_table_size等配置和服务器可用内存限制。内存不足或引发操作系统换页时,预期的性能优势会明显下降。 - 使用固定长度的行存储格式,不支持
BLOB和TEXT字段,设计表结构时需要检查字段类型限制。
MEMORY 表与 MySQL 执行复杂查询时使用的内部临时表不是同一个概念。内部临时表由优化器和内部临时表引擎管理,不能因为查询产生了临时结果就认为应该创建 MEMORY 业务表。
常见引擎对比
MySQL 存储引擎
| 对比项 | InnoDB | MyISAM | MEMORY |
|---|---|---|---|
| 数据位置 | 以表空间文件为主,并配合内存缓冲 | 磁盘文件 | 表数据位于内存 |
| 事务 | 支持 | 不支持 | 不支持 |
| 常规锁粒度 | 行级锁为主,也存在间隙锁、表级元数据锁等 | 表级锁 | 表级锁 |
| MVCC | 支持 | 不支持 | 不支持 |
| 外键 | 支持 | 不支持 | 不支持 |
| 常用索引 | B-tree、全文、空间索引 | B-tree、全文、空间索引 | Hash、B-tree |
| 崩溃后的数据恢复能力 | 支持崩溃恢复 | 有限,可能需要检查或修复表 | 表数据丢失 |
| 典型用途 | 绝大多数持久化业务表 | 旧系统兼容或经过验证的特殊场景 | 可丢失的临时工作数据、只读缓存 |
表中的“行级锁为主”是对 InnoDB 常规数据访问的概括,不表示 InnoDB 只存在行锁。DDL、意向锁、自动增量锁和元数据锁等场景仍可能影响整张表或更多会话。
常见数据库及其存储实现
| 数据库产品 | 数据模型 | 默认或主要存储实现 | 存储特点 |
|---|---|---|---|
| MySQL | 关系型 | InnoDB | 事务型、持久化,支持 MVCC;同时可以按表选用其他存储引擎 |
| PostgreSQL | 关系型 | heap 表访问方法 |
事务型、持久化,通过 MVCC 和 WAL 维护并发访问与故障恢复 |
| MongoDB | 文档型 | WiredTiger | 持久化,使用内存缓存、检查点和压缩,并提供文档级并发控制 |
| Redis | 键值与数据结构型 | 内置内存数据结构 | 内存优先,可以选择 RDB 快照、AOF 日志或二者组合进行持久化 |
这里比较的是完整数据库产品采用的主要存储实现,不表示 PostgreSQL 或 MongoDB 属于 InnoDB,也不表示 Redis 使用 MySQL 的 MEMORY 引擎。它们只能按照事务、持久化方式和主要数据位置等特征进行横向比较。
存储引擎选择
选择存储引擎时,应先确定事务一致性、并发写入、故障恢复、外键、索引类型、数据持久性和容量限制等要求,再结合真实工作负载进行测试。
- 通用业务表优先选择 InnoDB:它提供事务、崩溃恢复、MVCC、行级锁和外键等完整能力,也是 MySQL 8.x 的默认选择。
- 只有数据允许丢失时才考虑 MEMORY:同时需要限制数据规模,确认字段与索引能力满足需求,并为服务重启后的数据重建做好准备。
- 不要仅凭“读取多”选择 MyISAM:现代 InnoDB 同样具备成熟的缓存和索引能力。只有兼容旧表、使用特定 MyISAM 能力或基准测试证明其确实合适时,才应考虑使用。
- 谨慎混用事务型与非事务型引擎:跨引擎操作的事务语义并不一致,备份、恢复和运维方式也可能不同。
- 以测量结果验证性能判断:数据规模、索引设计、SQL、并发比例、缓存命中率和硬件环境通常比引擎名称本身更能决定实际性能。