一、MySQL怎么学:体系化学习路线
学习MySQL,建议按以下三个层次逐步深入:
1. 前置基础(必须掌握)
-
全面理解MySQL架构(本篇重点)
-
索引底层数据结构与算法
-
Explain详解与索引最佳实践
-
索引优化实战(一、二)
2. 进阶理解(深入内核)
-
事务隔离级别与锁机制
-
MVCC与BufferPool缓存机制
-
各种日志实现机制(redo log、binlog、undo log)
-
MySQL全局优化与MySQL 8.0新特性
3. 集群架构(高可用扩展)
- MySQL 8集群架构(一、二)
二、一条SQL查询语句是如何执行的?
我们先来看一个最简单的查询:
SELECT * FROM user WHERE id = 10;
它的执行流程如下图所示,分为Server层和存储引擎层两大模块:
客户端 → 连接器 → 查询缓存 → 分析器 → 优化器 → 执行器 → 存储引擎
2.1 连接器
负责客户端连接管理、权限验证等。常用命令:
mysql -h$ip -P$port -u$user -p
长连接 vs 短连接:
-
长连接:连接后持续使用,减少重复连接开销,但可能导致内存泄漏
-
短连接:每次查询完断开,下次重连,适合低频访问
连接池建议:
生产环境推荐使用连接池(如HikariCP、Druid),避免频繁创建连接,提升并发性能。
2.2 查询缓存(MySQL 8.0已移除)
在MySQL 5.7中,查询缓存用于缓存SELECT语句结果,key为SQL语句,value为结果集。
但在高并发更新场景下,缓存命中率极低,且维护成本高,因此在MySQL 8.0中已被彻底移除。
2.3 分析器
如果没有命中缓存,SQL语句会进入分析器,分为两步:
-
词法分析:识别SQL关键字、表名、列名等
-
语法分析:判断SQL是否符合语法规则
如果语法错误,会报错:
ERROR 1064 (42000): You have an error in your SQL syntax...
思考题:如果执行
SELECT * FROM T WHERE k=1,但表中没有k列,是在哪个阶段报错?
答案:分析器阶段。
2.4 优化器
优化器负责选择最优执行计划,例如:
-
选择哪个索引
-
多表JOIN时决定连接顺序
示例:
SELECT * FROM t1 JOIN t2 USING(ID) WHERE t1.c=10 AND t2.d=20;
优化器会评估两种方案,选择扫描行数少、成本低的方案。
2.5 执行器
执行器负责调用存储引擎接口执行查询,并在执行前进行权限校验。
即使命中缓存,也会在返回结果前进行权限验证。
三、一条SQL更新语句是如何执行的?
更新语句同样会走查询的流程,但多了两个关键日志模块:
-
redo log(重做日志):InnoDB引擎特有,物理日志,保证crash-safe
-
binlog(归档日志):Server层实现,逻辑日志,用于数据归档与复制
3.1 redo log(粉板记账法)
InnoDB使用WAL技术(Write-Ahead Logging) ,先写日志,再写磁盘。
redo log是循环写入的,固定大小(如4个文件,每个1GB),通过write pos和checkpoint指针控制写入与擦除。
3.2 binlog(归档账本)
binlog是逻辑日志,记录的是SQL语句的原始逻辑,支持追加写入,用于数据恢复和主从复制。
3.3 更新流程示例
以更新语句为例:
UPDATE T SET c=c+1 WHERE ID=2;
执行步骤:
-
执行器找引擎取ID=2这一行(若不在内存则从磁盘读入)
-
执行器将c值加1,调用引擎写入新行
-
引擎更新内存,并写入redo log(prepare状态)
-
执行器写binlog
-
执行器调用引擎提交事务,redo log改为commit状态
四、两阶段提交(内部XA)
为了保证redo log和binlog的逻辑一致性,MySQL使用两阶段提交:
4.1 如果不使用两阶段提交,会出现什么问题?
-
先写redo log后写binlog:redo log中事务已提交,binlog丢失,从库恢复时数据不一致
-
先写binlog后写redo log:binlog有记录,redo log未提交,主库恢复后事务丢失,从库多出一条数据
4.2 崩溃恢复逻辑
-
如果redo log有commit标识,直接提交
-
如果只有prepare,则检查对应binlog是否完整:
-
binlog完整 → 提交事务
-
binlog不完整 → 回滚事务
-
4.3 redo log与binlog的关联
通过XID字段关联。崩溃恢复时,按顺序扫描redo log:
-
有prepare + commit → 提交
-
只有prepare → 去binlog中查找对应XID的事务
五、Java开发者需要注意的几点
5.1 连接管理
推荐使用连接池,避免频繁创建连接,注意设置合理的wait_timeout。
5.2 事务控制
理解innodb_flush_log_at_trx_commit和sync_binlog参数对数据一致性的影响。
5.3 数据恢复
定期备份 + binlog归档,可实现任意时间点的数据恢复。误删数据后恢复流程:
-
取最近一次全量备份
-
重放binlog到误删前一刻
六、总结
MySQL的架构清晰分为Server层和存储引擎层,SQL执行过程依次经过连接、缓存、分析、优化、执行等阶段。更新语句额外依赖redo log和binlog两大日志系统,通过两阶段提交保证数据一致性。