{T}

MySQL 体系结构与存储引擎

0. 引言

MySQL 是互联网时代最普及的开源关系型数据库。理解 MySQL 的体系结构,是掌握索引、事务、锁、高可用等一切后续主题的前提。本文以 MySQL 8.0(当前主流生产版本,8.0 与 8.4 LTS)为基准,解析 MySQL 的层级架构、一条 SQL 的完整执行链路,以及 InnoDB 存储引擎的内存/线程/物理结构,并对齐 5.7 → 8.0 的关键演进。

1. 总体架构:Server 层与存储引擎层

图表渲染中…

MySQL 的架构精髓是插件式存储引擎:Server 层(连接管理、解析、优化、缓存)与存储引擎层解耦,任何实现了统一接口的引擎都可以接入 MySQL。

层级核心模块职责
Server 层Connection Pool管理连接线程、用户认证与权限校验
Server 层ParserSQL 语法解析,生成解析树(语法错误在此暴露)
Server 层Optimizer生成执行计划、选择索引、决定连接顺序
Server 层执行引擎按执行计划调用存储引擎 API
引擎层InnoDB事务、行锁、MVCC、崩溃恢复(默认引擎)
引擎层MyISAM无事务、表锁、只读场景的遗留选择
物理层文件系统表空间文件、redo/undo 日志、binlog、慢查询日志

8.0 一个重要变化:查询缓存(Query Cache)被彻底移除(8.0.3 起废弃)。5.7 时代"相同 SQL 直接返回缓存结果"的优化在写多读少、缓存失效频繁的场景下弊大于利,官方在 8.0 直接删除该组件。

2. 一条 SQL 的完整执行链路

SELECT 为例,SQL 的生命周期如下:

图表渲染中…

各步骤要点:

  1. 连接:客户端通过 TCP 或 Unix Socket 建立连接,Connection Pool 为每个连接分配线程;认证失败在此阶段被拒绝(8.0 默认 caching_sha2_password 认证插件)。
  2. 解析:Parser 将 SQL 拆分为 Token,构建解析树。此阶段只检查语法,不检查表是否存在。
  3. 预处理:语义检查——表/列是否存在、权限是否足够、* 展开。
  4. 优化:Optimizer 基于统计信息(mysql.innodb_table_stats 等)选择访问路径。这是 DBA 通过 EXPLAIN 能干预的关键环节
  5. 执行:执行引擎通过存储引擎 API 逐行读取数据(InnoDB 的读取单位是 16KB 数据页)。
  6. 返回:Server 层完成 ORDER BY/GROUP BY/LIMIT 等操作后返回结果集。

DML 与 SELECT 的差异UPDATE/DELETE 在执行阶段会先定位记录,再在事务上下文中修改并生成 redo/undo 日志,最后在提交时刷盘——比 SELECT 多出事务与日志两条链路(详见《深入理解事务与锁机制》)。

3. 存储引擎全景

MySQL 支持多种存储引擎,通过 SHOW ENGINES 查看:

引擎事务锁粒度特点现状
InnoDB✅ ACID行锁MVCC、聚簇索引、崩溃恢复默认引擎(5.5.5+),绝对主流
MyISAM表锁压缩、全文索引(旧版)遗留;8.0 中仍可用但不建议
Memory表锁数据全内存,重启丢失临时表/缓存场景;8.0 起临时表改由 InnoDB/临时引擎承担
Archive行锁高压缩、只支持 INSERT/SELECT日志归档场景
CSV表锁数据即 CSV 文件数据交换场景

8.0 中 MyISAM 系统表全部被 InnoDB 取代(数据字典统一存储),且官方明确 InnoDB 是唯一推荐的全功能引擎。MySQL 8.0 的临时表默认使用 InnoDB 或专用临时引擎(TempTable),不再依赖 Memory 引擎。

4. InnoDB 架构:实例层与物理层

4.1 总体结构

图表渲染中…

4.2 内存结构

Buffer Pool(缓冲池)——InnoDB 性能的心脏:

  • 缓存数据页、索引页、undo 页、自适应哈希索引(AHI)、锁信息等;
  • 采用 LRU 改进算法(分 old/new 两段:新数据先入 old 段,第二次访问才晋升 new 段),防止全表扫描把热点数据挤出去;
  • 8.0 支持动态调整innodb_buffer_pool_size 可在运行时修改(5.7+),且支持多实例(innodb_buffer_pool_instances,8.0 默认按 128MB 分片);
  • 配置经验:单机单实例时设为物理内存的 60%~80%;通过 SHOW GLOBAL STATUS LIKE '%buffer_pool%' 观察命中率与等待时间。

Redo Log Buffer:暂存数据修改产生的 redo 日志,默认 16MB(innodb_log_buffer_size),事务提交时按 innodb_flush_log_at_trx_commit 策略刷盘(0/1/2)。

Double Write Buffer(双写缓冲):解决"页撕裂"——数据页写一半时断电,产生半页损坏。双写先把整页副本写入双写区域再落盘,崩溃恢复时可用副本修复。8.0.20+ 支持独立双写文件(innodb_doublewrite_dir),并可在不支持的操作系统关闭(innodb_doublewrite=OFF)。

4.3 后台线程

线程职责演进
Master Thread主循环调度:1s/10s 周期任务(刷日志、刷脏页、合并 insert buffer、purge)5.6 前"全能",5.6+ 逐步拆分
Page Cleaner Thread专职脏页刷新(可配置多个)5.6 引入,解决主线程刷脏阻塞
Purge Thread回收已提交事务的 undo 页5.6 引入,可多实例
Read/Write Thread并行读写数据文件(innodb_read_io_threads/innodb_write_io_threads提升 IO 吞吐
Redo Log Thread刷新 redo 日志缓冲到磁盘8.0.30+ 独立线程

4.4 物理结构

8.0 的物理文件布局相比 5.7 有重大调整:

文件5.78.0
数据字典ibdata1 + 各表 .frm统一存储在 InnoDB 数据字典(原子 DDL:DDL 要么成功要么回滚,不再有 .frm 与 .ibd 不一致问题)
Undo 日志ibdata1 + 独立 undo 表空间完全独立:innodb_undo_tablespacesinnodb_undo_directoryinnodb_max_undo_log_sizeinnodb_undo_log_truncate(默认开启,支持运行时截断回收)
Redo 日志ib_logfile0/1(固定大小)#innodb_redo 目录 + innodb_redo_log_capacity(8.0.30+ 容量管理,默认 100MB,动态扩展)
表空间独立表空间默认开启支持 CREATE TABLESPACE 通用表空间、CREATE UNDO TABLESPACE ADD DATAFILE 'xxx.ibu' 动态创建

redo 日志容量管理(8.0.30+)innodb_redo_log_capacity 取代了 innodb_log_file_size 的固定文件配置,redo 文件在 #innodb_redo 目录中按需增减。可通过 performance_schema.innodb_redo_log_files 查询每个文件的 LSN 区间与使用率:

sql
SELECT FILE_ID, START_LSN, END_LSN, SIZE_IN_BYTES, IS_FULL
FROM performance_schema.innodb_redo_log_files;

检查点(checkpoint):redo 是循环复用的。当 checkpoint_age(检查点 LSN 与最新 LSN 之差)逼近容量上限时,InnoDB 强制刷新脏页推进检查点——redo 太小会导致频繁强制 checkpoint,拖慢写入;设置过大则崩溃恢复时间变长。生产建议监控 Innodb_redo_log_capacity 相关指标,写入密集场景通常需要 2-8GB。

5. ARIES 三原则:InnoDB 的恢复基石

InnoDB 的崩溃恢复基于经典的 ARIES 算法,核心三原则:

  1. WAL(Write Ahead Logging):先写日志、后写数据。事务提交时 redo 落盘成功即不丢失(配合刷新策略),后续由 checkpoint 保证磁盘数据与日志一致;
  2. Redo 记录变更后的值:崩溃后用 redo 前滚(redo)所有已提交但未落盘的修改;
  3. Undo 记录变更前的值:崩溃后用 undo 回滚(undo)所有未提交事务的修改,同时支撑 MVCC 多版本读。
图表渲染中…

这也是"为什么 MySQL 断电不丢已提交数据"的根本原因:提交的语义 = redo 已落盘,而不是数据页已落盘。

6. InnoDB vs MyISAM:功能与性能对比

维度InnoDBMyISAM
事务(ACID)
锁粒度行锁 + 间隙锁仅表锁
隔离级别4 种,默认 RR(可重复读)
MVCC
崩溃恢复✅(redo + undo)❌(需手动修复)
外键
聚簇索引✅(数据按主键组织)❌(堆表 + 索引文件分离)
全文索引✅(8.0 支持中文分词)
压缩✅(页压缩/透明页压缩)✅(表压缩)
适用场景通用 OLTP,绝对首选只读/归档类历史遗留

性能差异:InnoDB 在读写混合场景随 CPU 核数近线性扩展(官方测试可达近 9000 TPS),而 MyISAM 因读写互斥、表锁串行,性能与核数无关(<500 TPS)。新表一律使用 InnoDB,MyISAM 只存在于历史系统中。

7. 小结

  • MySQL = Server 层(连接/解析/优化/执行)+ 插件式存储引擎层,8.0 移除查询缓存、数据字典统一入 InnoDB;
  • SQL 执行链路:连接→解析→预处理→优化→执行→返回,DBA 的干预点主要在优化器(索引与执行计划);
  • InnoDB 架构:Buffer Pool(改进 LRU)+ 双写 + 多线程刷盘,物理层 8.0 全面重构(原子 DDL、独立 undo、动态 redo 容量);
  • ARIES 三原则(WAL + redo 前滚 + undo 回滚)是崩溃恢复的理论根基;
  • 引擎选型:InnoDB 一统天下,MyISAM 只读遗留。

下一章深入事务与锁机制:隔离级别、MVCC、行锁/间隙锁/临键锁与死锁。