执行器工作流程
执行器的角色
执行器(Executor)是 MySQL 查询执行链路的最后一环。它的职责很简单:按照优化器生成的执行计划,调用存储引擎的接口,真正去读写数据。
graph LR
A[优化器] --> B[执行计划]
B --> C[执行器]
C --> D[存储引擎<br/>InnoDB]
D --> E[数据文件]
C --> F[返回结果给客户端]
执行流程详解
以这条 SQL 为例:
SELECT * FROM user WHERE id = 10;
Step 1: 权限校验
sequenceDiagram
participant Exec as 执行器
participant Cache as 权限缓存
Exec->>Cache: 检查当前用户<br/>是否有user表的SELECT权限
Cache-->>Exec: ✅ 有权限
Note over Exec: (无权限则直接报错)
Step 2: 调用引擎接口
执行器根据执行计划,调用存储引擎的取数据接口:
-- 如果走主键索引
执行器: "InnoDB,给我取 user 表中 id=10 的那一行"
InnoDB: 通过B+树定位id=10的数据页
InnoDB: 返回该行数据给执行器
Step 3: 条件过滤
-- 如果走的是全表扫描(没有索引)
执行器: "InnoDB,给我取 user 表的第一行"
InnoDB: 返回 row_1
执行器: "id=10? 不是,跳过"
执行器: "InnoDB,再给我下一行"
InnoDB: 返回 row_2
执行器: "id=10? 不是,跳过"
-- 循环直到找到 id=10 的行
Step 4: 结果返回
flowchart LR
A[逐行过滤<br/>满足条件的行] --> B[存入结果集]
B --> C[发送给客户端]
C --> D{结果集是否<br/>超过net_buffer_length?}
D -->|是| E[分批次发送]
D -->|否| F[一次性发送]
不同场景的执行差异
场景一:主键查询
-- 执行器调用引擎的"索引唯一扫描"接口
SELECT * FROM user WHERE id = 10;
流程:
执行器 → InnoDB.row_search_for_mysql(index=PRIMARY, key=10)
← InnoDB 返回单行数据
→ 直接返回给客户端(无条件过滤,因为已精确匹配)
场景二:全表扫描
-- 执行器调用引擎的"表扫描"接口,逐行过滤
SELECT * FROM user WHERE name = '张三'; -- name没有索引
流程:
执行器 → InnoDB.表扫描first() → row1
→ name='张三'? NO, skip
→ InnoDB.表扫描next() → row2
→ name='张三'? YES → 加入结果集
→ ...直到最后一行
场景三:带索引查询
-- 执行器调用引擎的"索引范围扫描"接口
SELECT * FROM user WHERE age > 18; -- age有索引
流程:
执行器 → InnoDB.index_first(age>18) → row_ages_19
→ 返回给执行器
→ 执行器判断是否还需要回表
→ 继续下一行...
慢查询日志中的执行器
-- 慢查询日志中记录了执行阶段的耗时
# Query_time: 2.500000 Lock_time: 0.000100
# Rows_sent: 100 Rows_examined: 1000000
SELECT * FROM user WHERE name = '张三';
- Rows_examined:执行器扫描的行数(从引擎获取的行数)
- Rows_sent:最终返回给客户端的行数
- 比例:Rows_examined 远大于 Rows_sent,说明效率低
执行器与存储引擎的接口
关键接口(handler 层):
| 接口 | 说明 |
|---|---|
ha_index_init() |
初始化索引扫描 |
ha_index_first() |
获取索引第一条记录 |
ha_index_next() |
获取索引下一条记录 |
ha_rnd_init() |
初始化全表扫描 |
ha_rnd_next() |
全表扫描下一条 |
ha_write_row() |
插入行 |
ha_update_row() |
更新行 |
ha_delete_row() |
删除行 |
面试要点
- 执行器是”执行者”而非”决策者”:决策是优化器做的
- 逐行过滤模式:全表扫描时是逐行调用引擎接口再过滤
- Rows_examined ≠ Rows_sent:前者是工作量,后者是产出
- 权限校验在开头:不满足权限直接报错,不进入引擎环节
一句话总结:执行器是 MySQL 的”打工仔”,优化器指哪它打哪。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容