深入Mysql(执行流程)
Select执行流程(理解mysql执行流程)
graph TD
B[连接器] --> C{查询缓存命中?}
C -->|是| D[返回缓存结果]
C -->|否| E[解析器]
E --> F[预处理器]
F --> G[优化器]
G --> H[执行器]
H --> I[存储引擎]
I --> J[返回结果]
J --> K[更新查询缓存]
style D fill:#bbf,stroke:#333
style J fill:#9f9,stroke:#333
执行过程遵从上图流程
- mysql分为server层和引擎层,其中连接器到执行器的部分属于server层
连接器
用于管理mysql连接,权限验证。通常我们优先使用长连接,并用连接池hold住以减少因频繁创建连接的损耗。
note:
- 验证用户名、密码、IP 权限(基于
mysql.user
表)
- 当建立连接后mysql将不再校验权限,因此中途如果权限发生变更已有的连接将不受影响;
- mysql的内存对象通常是和连接绑定,因此如果长时间持有连接不释放则可能会导致内存泄漏甚至因oom被操作系统shutdown;
- 可以定时断开并重连连接;
- mysql(5.7)以后支持reset连接从而释放内存;
- mysql的连接如果长时间不使用则会删除自动断开(默认阈值8小时);
缓存(MySQL 8.0已移除)
缓存以key-value键值对形式存在
- key:sql语句
- value:数据
场景:
- 查询缓存
- 执行
SELECT
语句前,先检查查询缓存是否命中。 - 如果命中,直接返回缓存结果(跳过后续步骤)。
- 执行
- 失效缓存
- 任何对表的修改(
INSERT
/UPDATE
/DELETE
)都会使该表的所有缓存失效。
- 任何对表的修改(
- 适用场景
- 适合读多写少的静态表(如系统配置表)
- MySQL 8.0 移除原因:缓存命中率低,维护缓存开销大,影响高并发性能。
解析器
对 SQL 语句进行 词法分析 + 语法分析,生成解析树(Parse Tree)
词法分析:
将 SQL 拆分成 关键字、表名、列名、运算符 等 Token。
例如
1
SELECT id FROM users WHERE age > 18
会被拆解为:
SELECT
(关键字)id
(列名)FROM
(关键字)users
(表名)WHERE
(关键字)age > 18
(条件表达式)
语法分析:
- 检查 SQL 是否符合 MySQL 语法规则(如
SELECT
拼写错误会在此报错)。 - 生成 解析树(Parse Tree),供优化器使用。
- 检查 SQL 是否符合 MySQL 语法规则(如
优化器
作用:基于 执行成本(Cost-Based Optimization, CBO) 选择最优执行计划。
详细流程:
优化策略:
- 决定 使用哪个索引(如
age
索引 vs.name
索引)。 - 决定 表的连接顺序(如
A JOIN B
vs.B JOIN A
)。 - 决定 是否使用临时表(如
GROUP BY
优化)。
执行计划生成:
生成
执行计划(Execution Plan),可通过
EXPLAIN
查看:sql
1
EXPLAIN SELECT * FROM users WHERE age > 18;
执行器
调用 存储引擎接口,执行优化器生成的计划,返回结果。
- 根据具体实现选择
MyISAM
和InnoDB
数据读取:
- 执行器调用引擎的接口,如:
InnoDB
:通过 B+树索引 或 全表扫描 查找数据。MyISAM
:直接从.MYD
文件读取数据。
事务支持:
InnoDB
支持事务(BEGIN
/COMMIT
/ROLLBACK
)。MyISAM
不支持事务。
锁机制:
InnoDB
支持 行锁,MyISAM
仅支持 表锁。
update执行流程(理解binlog和redolog)
和select基本一致,但有以下不同点
- 根据update的table来决定失效哪个缓存
- 会分别写入redoLog和BinLog
RedoLog
由innodb存储引擎实现,是实现系统崩溃回滚的重要实现。
如何使用?
redolog是一个文件组,存储一系列redolog日志,默认2个。它们由两个指针write-point
和check-point
维护,write-point
用于标记将来要写的位置,每写一条往后移动一格。check-point
同理,当表数据被同步到数据库磁盘文件中后他将往后移动一格,并清除之前的数据。
write-point
追上check-point
,说明redolog写满。会导致阻塞。check-point
追上write-point
,说明redolog已无内容需要同步。
BinLog
- 位语server层的log,记录每一次操作,类似redis的AOF机制。
- 同步支持:从库服务器会读取binlog来同步主库的操作。
和redolog区别:
- redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
- redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
- redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
Log流程
- 根据用户传入的where条件,从引擎中获取数据;
- 此过程会遍历B+树,且每次都会先从内存buffer中获取,没有则会去磁盘文件中读取数据并加载到buffer。
- 将获取的结果回传给server层,再由执行器对这行数据进行修改;并将修改后的数据通过调用引擎接口保存。
- 引擎更新数据到buffer内存,并写入一条redolog记录修改且此次redolog数据行的状态为prepare。
- 执行器生成这个操作的binlog。
- 执行器调用引擎提交当前事务,将redolog的prepare状态改为commit状态。
深入Mysql(执行流程)
https://andrewjiao.github.io/2023/06/18/mysql/深入Mysql(执行流程)/