前三阶段的学习,我们大多聚焦在"怎么写 SQL"、"怎么建表"、"怎么用 Java 连 MySQL"这些偏应用层的技能上。从本篇开始,我们将进入 MySQL 的内核世界,理解它内部是如何组织和运转的。理解了架构,你才能明白为什么有些查询快、有些慢,为什么 InnoDB 是默认引擎,以及如何根据自己的业务场景做出正确的技术选择。
本文将带你了解:
- MySQL 的四层逻辑架构
- 各层的主要职责和组件
- 几种常见存储引擎的特点与对比(InnoDB、MyISAM、MEMORY 等)
- 如何选择合适的存储引擎
- 如何查看表使用的引擎及引擎状态
- 动手实战:创建不同引擎的表并观察其差异
1. MySQL 的"四层小楼":整体架构一览
MySQL 的设计非常有层次感,我们可以把它看成一座四层楼,从上到下分别是:
- 连接层 ------ 接待客户
- 服务层 ------ 分析需求并制定执行计划
- 存储引擎层 ------ 实际干活的人
- 文件系统层 ------ 把结果持久化到磁盘
下面逐层来认识。
1.1 连接层:握手与线程
连接层负责与客户端建立连接、验证身份、分配线程。当你执行 mysql -u root -p 时,就触发了这一层的工作流程:
- TCP 握手:客户端与 MySQL 服务端建立网络连接。
- 身份验证:核对用户名、密码、主机权限。
- 线程分配:MySQL 为每个连接分配一个线程,后续这个连接的所有 SQL 都由该线程处理。
- 连接池管理:MySQL 内部有一个线程池(不同于应用侧的连接池),负责复用线程以降低频繁创建/销毁的开销。
可以通过 SHOW PROCESSLIST 查看当前所有连接及其状态:
sql
SHOW FULL PROCESSLIST;
1.2 服务层:大脑与指挥中心
服务层是 MySQL 的核心,绝大多数功能都在这一层实现。即使你从未感知过它,它也在默默工作。
主要组件:
- 查询缓存(Query Cache):MySQL 8.0 已移除该功能,因为在高并发下它反而会成为瓶颈。早期版本会将 SELECT 语句及其结果以 K-V 形式缓存,表数据变更后缓存失效。
- 解析器(Parser):对 SQL 语句进行词法分析、语法分析,生成一棵"解析树"。如果 SQL 有语法错误,就是在这里被揪出来的。
- 预处理器(Preprocessor):检查解析树中的表名、列名是否存在,权限是否满足。
- 查询优化器(Optimizer) :这是服务层最复杂、最重要的模块。它负责为一条 SQL 生成多种可能的执行路径,估算每种路径的代价,并选出代价最低的作为"执行计划"。我们用的
EXPLAIN就是查看优化器决策结果的工具。 - 执行器(Executor):按照执行计划,逐条调用存储引擎提供的接口(Handler API)来读写数据。
- 管理服务与工具:备份、恢复、安全、迁移等功能的入口。
你可以把服务层想象成一个项目经:它接收客户的需求(SQL),理解需求(解析),制定方案(优化),然后安排具体的工人(存储引擎)去执行。
1.3 存储引擎层:真正的数据操盘手
存储引擎是 MySQL 架构中最具特色的部分。它可插拔------你可以为不同的表选择不同的存储引擎,而服务层通过统一的 API 与它们交互,无需关心底层的数据存储细节。
这种设计的巨大优势:
- 你可以在同一个数据库中,为事务型核心表使用 InnoDB,为只读的日志归档表使用 MyISAM(当然现在极少这么做了),为临时计算使用 MEMORY 引擎。
- 第三方也可以开发自己的存储引擎(如 TokuDB、MyRocks 等)。
1.4 文件系统层:物理持久化
最底层就是操作系统上的文件。存储引擎将数据最终写入磁盘文件,这些文件可能包括:
- 表数据文件(
.ibd) - 表结构文件(
.frm,8.0 后被data dictionary取代) - 日志文件(
redo log、undo log、binlog等) - 配置文件等
这部分我们在第四阶段后续文章会深入探究。
一张图总结(文字版):
┌──────────────────────────────────────┐
│ 客户端 / JDBC / CLI │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ 连接层:身份验证、线程分配 │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ 服务层:解析、优化、执行 │
│ (解析器 → 优化器 → 执行器) │
└──────────────┬───────────────────────┘
│ Handler API
┌──────────────▼───────────────────────┐
│ 存储引擎层:InnoDB / MyISAM / ... │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ 文件系统层:.ibd, .frm, redo log... │
└──────────────────────────────────────┘
2. 常见存储引擎对比
MySQL 支持多种存储引擎,我们重点介绍最常遇到的几种。
2.1 InnoDB ------ 现在的绝对主力
自 MySQL 5.5 起,InnoDB 成为默认存储引擎。它的核心特点:
- 支持事务(ACID):通过 Redo Log、Undo Log 和 MVCC 实现,是目前唯一内置支持事务的标准引擎。
- 行级锁:并发读写时锁粒度更细,高并发场景优势明显。
- 外键支持:保障引用完整性。
- 聚簇索引:数据按主键顺序存储,主键查询和范围查询很快。
- 崩溃恢复:通过 Redo Log 实现,即使断电也能保证已提交数据不丢失。
- 支持热备份 :配合
mysqldump、Xtrabackup等工具可在线备份。
适用场景 :几乎一切 OLTP(在线事务处理)场景,如电商订单、银行交易、社交互动。除非有特殊理由,否则默认用 InnoDB 就对了。
2.2 MyISAM ------ 曾经的王者
在 MySQL 早期(5.5 之前),MyISAM 是默认引擎。它的特点:
- 不支持事务:没有 COMMIT/ROLLBACK,数据一致性靠应用层保证。
- 表级锁:任何写操作都会锁住整张表,并发写入性能极差。
- 不支持外键:引用完整性需应用自行维护。
- 存储结构简单 :每张表对应三个文件------
.frm(定义)、.MYD(数据)、.MYI(索引)。 - 查询速度较快:在少量并发、读写比极高的场景下(如数据仓库、日志归档),其表扫描性能有时略优于 InnoDB(因为表结构更简单,无事务开销)。
- 支持全文索引:InnoDB 在 5.6 后才支持,但在早期这是 MyISAM 的一大优势。
当前定位 :MySQL 8.0 已逐步淘汰 MyISAM(系统表全部转为 InnoDB)。新项目不应该再使用 MyISAM,除非你维护的是一个无法升级的遗留系统。
2.3 MEMORY(HEAP) ------ 极速但易失
MEMORY 引擎将数据全部存储在内存中,重启后数据丢失(表结构保留)。
- 速度极快:所有操作都在内存完成。
- 默认使用 HASH 索引(也可指定 BTREE),适合等值查询。
- 不支持事务、外键。
- 表级锁。
- 大小受
max_heap_table_size参数限制(默认 16MB),不能无限增长。
适用场景:缓存表、临时结果集、会话数据等不需要持久化且对速度极度敏感的场景。但注意,在现代架构中,这类需求通常由 Redis 等专用缓存实现,MEMORY 引擎用途已较少。
2.4 其他引擎速览
| 引擎 | 特点 | 使用场景 |
|---|---|---|
| CSV | 数据以 CSV 文件存储,可用 Excel 直接打开 | 数据交换、快速导出 |
| ARCHIVE | 压缩存储,只支持 INSERT 和 SELECT,不支持 UPDATE/DELETE | 日志归档、审计数据 |
| BLACKHOLE | 写入即丢弃(像 /dev/null) | 中继复制、测试 |
| FEDERATED | 访问远程数据库的表,类似透明网关 | 分布式环境(已逐渐被分布式方案替代) |
| NDB | MySQL Cluster 使用的分布式引擎 | 高可用、高冗余的电信级应用 |
3. 如何选择存储引擎?
没有哪个引擎是绝对"最好"的,但有"最适合当前场景"的。以下是一条简明的决策路径:
- 是否需要事务? 是 → InnoDB;否 → 继续下一步。
- 数据是否需要持久化? 否 → 考虑 MEMORY 或 Redis;是 → InnoDB。
- 是否只有 INSERT 和 SELECT,且数据量极大又不修改? 是 → 可考虑 ARCHIVE(但通常仍推荐 InnoDB 并开启页压缩)。
- 是否需要外键约束? 是 → 只能用 InnoDB。
一句话总结:在 95% 的场景下,直接使用 InnoDB 即可。 现代 MySQL 的优化方向全部围绕 InnoDB 展开,MyISAM 等引擎已经不再积极维护。
4. 查看与设置存储引擎
4.1 查看支持的引擎
sql
SHOW ENGINES;
结果中 Support 列显示 DEFAULT 的就是当前默认引擎(通常为 InnoDB)。
4.2 查看某张表的引擎
sql
SHOW TABLE STATUS LIKE 'books'\G
关注 Engine 字段。
或通过 INFORMATION_SCHEMA:
sql
SELECT TABLE_NAME, ENGINE FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'library_db';
4.3 设置表的引擎
建表时指定:
sql
CREATE TABLE test_myisam (
id INT PRIMARY KEY,
val VARCHAR(100)
) ENGINE=MyISAM;
修改已有表的引擎:
sql
ALTER TABLE test_myisam ENGINE=InnoDB;
注意:转换引擎是一个代价较高的 DDL 操作,会重建整张表,大表请用在线变更工具(如
pt-online-schema-change)。
5. 实战:观察不同引擎的差异
我们来做一个小实验,直观感受 InnoDB 与 MyISAM 在事务支持和锁粒度上的差异。
5.1 创建两张测试表
sql
CREATE TABLE innodb_test (
id INT PRIMARY KEY,
name VARCHAR(20)
) ENGINE=InnoDB;
CREATE TABLE myisam_test (
id INT PRIMARY KEY,
name VARCHAR(20)
) ENGINE=MyISAM;
INSERT INTO innodb_test VALUES (1, 'hello');
INSERT INTO myisam_test VALUES (1, 'hello');
5.2 事务支持对比
InnoDB(在两个会话中分别执行):
会话 A:
sql
START TRANSACTION;
UPDATE innodb_test SET name = 'world' WHERE id = 1;
-- 不提交
会话 B:
sql
SELECT * FROM innodb_test WHERE id = 1; -- 默认隔离级别 REPEATABLE READ 下,读到的是 'hello'(未提交的修改不可见)
会话 A 回滚:
sql
ROLLBACK;
会话 B 再查,数据恢复原样。这就是事务隔离性的体现。
MyISAM:
会话 A:
sql
-- MyISAM 没有事务,直接 UPDATE
UPDATE myisam_test SET name = 'world' WHERE id = 1;
会话 B 立即就能读到 'world',且一旦执行无法回滚。
5.3 锁粒度对比
MyISAM 在执行 UPDATE 时会对整张表加写锁,此时其他会话的读操作也会阻塞(写锁排斥读锁)。你可以用两个会话测试:
会话 A:
sql
UPDATE myisam_test SET name = 'aaa' WHERE id = 1;
-- 故意不立即提交(实际上 MyISAM 也没有事务,这句执行后锁立即释放?不,由于安全更新模式或显式 LOCK TABLES 才会持续锁;默认 MyISAM 写操作完成后会立即释放锁。为了演示,可以使用 LOCK TABLES)
LOCK TABLES myisam_test WRITE;
会话 B:
sql
SELECT * FROM myisam_test; -- 会阻塞,直到会话 A 执行 UNLOCK TABLES;
而对于 InnoDB,只锁住被修改的行,其他行可以正常读写。
清理:
sql
DROP TABLE innodb_test, myisam_test;
6. 小结
MySQL 的架构设计堪称数据库设计的典范,它的分层可插拔结构使得核心服务与存储实现解耦,为不同应用场景提供了灵活的引擎选择。
- 四层架构:连接层(握手分配线程)→ 服务层(解析/优化/执行,是大脑)→ 存储引擎层(真正存取数据,可插拔)→ 文件系统层(持久化)。
- InnoDB 是现今的绝对首选:支持事务、行锁、外键、崩溃恢复,几乎覆盖所有 OLTP 需求。
- MyISAM 已退出历史舞台,只存在于遗留系统中;MEMORY 用于临时缓存但通常被外部缓存代替。
- 可以通过
SHOW ENGINES和SHOW TABLE STATUS查看引擎信息,用ALTER TABLE ... ENGINE=...转换引擎。
理解了整体架构,我们就有了后续深入 InnoDB 物理存储、内存结构、日志系统的地图。下一篇文章,我们将聚焦于 InnoDB 的物理世界,探索表空间、段、区、页这些概念,看清 InnoDB 在磁盘上究竟是怎么存放数据的。
思考题:
- 为什么说优化器是服务层的"大脑"?
EXPLAIN对它产出的执行计划有什么作用? - 如果有一张存储日志的表,只有 INSERT 和 SELECT,没有 UPDATE/DELETE,你觉得应该用 InnoDB 还是 MyISAM?现在(MySQL 8.0)呢?
- 查看你的
library_db中每张表当前使用的引擎,把它们都统一为 InnoDB。
参考资料
- MySQL 8.0 Reference Manual - The MySQL Architecture
- MySQL 8.0 Reference Manual - Storage Engines
- MySQL 8.0 Reference Manual - InnoDB Storage Engine