执行器工作流程

执行器工作流程

执行器的角色

执行器(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
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容