从零起步学习MySQL || 第五章:select语句的执行过程是怎么样的?(结合源码深度解析)

🧩 一、整体流程概览

MySQL 的执行过程可以分为两大部分:

  1. Server 层(SQL 层):负责连接管理、解析、优化、执行等逻辑。

  2. 存储引擎层(Engine 层):负责数据的存取,比如 InnoDB、MyISAM 等。

可以理解为:

Server 层决定 "查什么、怎么查",

存储引擎层负责 "去磁盘拿数据回来"。


⚙️ 二、执行流程的 7 个核心阶段

假设你执行了:

复制代码
SELECT name FROM user WHERE id = 1;

我们来看看 MySQL 内部经历的全过程。


① 连接器(Connection Manager)

  • 当客户端(比如 Navicat、Java 应用中的 JDBC)发起连接时,MySQL 首先由 连接器 处理。

  • 验证用户名、密码,建立 TCP 连接。

  • 如果连接成功,会分配一个线程来处理这个客户端的后续请求。

🧠 知识点

  • 长连接(connection pool)可以复用连接,避免频繁建立/销毁 TCP。

  • 但长连接可能导致 内存膨胀 (因为线程上下文缓存),可通过 mysql_reset_connection() 重置。这一过程无需重连和重新做权限验证,但是会将连接恢复至刚刚创建完的状态。


② 查询缓存(Query Cache)【MySQL 8.0 已移除】

  • 旧版本 MySQL(<8.0)会先看这条 SQL 是否在缓存中。

  • 如果命中缓存,直接返回结果。

  • 因为更新任意表会导致缓存失效,所以性能反而不稳定,现代 MySQL 不再使用


③ 解析器(Parser)

  • 词法分析:把 SQL 拆成 token(如 SELECTnameFROMuser 等)(分析关键字)。

  • 语法分析:生成 语法树(Parse Tree)

    • 检查语法是否正确(例如是否缺少关键字等)。

    • 如果语法有问题,这里就会报错

🧠 类比理解

就像编译器在编译源代码时,先把源码拆解成语法结构。


④ 预处理器(Preprocessor)

  • 进一步验证 SQL 的合法性:

    • 表、字段是否存在;

    • 用户是否有权限;

    • 名称是否有歧义。

    • 将 * 修改为所有列

根据源码发现,如果有表或字段不存在,会在语法分析后,预处理前出现报错


⑤ 优化器(Optimizer)

这是 MySQL 智能的地方 ------ 选择最优执行计划

优化器的主要任务:

  • 确定使用哪个索引;

  • 确定表连接顺序;

  • 是否可以利用索引覆盖;

  • 是否可以进行查询重写、常量折叠等。

📘 示例

复制代码
SELECT * FROM user WHERE age > 20 AND name = 'Tom';

优化器可能决定:

  • 使用 name 索引(因为选择性更高),

  • 先过滤出 name='Tom' 再判断 age > 20

🧠 查看优化器决策

复制代码
EXPLAIN SELECT * FROM user WHERE age > 20 AND name = 'Tom';

可查看执行计划、索引使用情况、行扫描数等。


⑥ 执行器(Executor)

索引下推

前提假设

假设 t_user 表有以下结构:

  • 主键:id(聚簇索引,存储完整行数据)。
  • 二级索引:idx_age(包含 age 列,且包含 reward ,即索引中存储了 agereward 的值)。
  • 数据示例(简化):
id age reward
1 21 50000
2 22 100000
3 23 80000
4 24 100000
5 25 120000

有索引下推时,reward = 100000 的判断会提前到存储引擎层,减少不必要的回表。过程如下:

步骤 1:Server 层发起查询,定位初始记录

Server 层调用存储引擎接口,要求找到满足 age > 20第一条二级索引记录 (即 age=21 对应的索引项,对应 id=1)。

步骤 2:存储引擎层提前过滤 reward 条件

存储引擎定位到 age=21 的二级索引记录后,不立即回表 ,而是先检查索引中包含的 reward 列:

  • 该记录的 reward=50000,不满足 reward=100000直接跳过这条索引记录,不回表。
步骤 3:遍历下一条索引记录,重复过滤

存储引擎继续取下一条 age > 20 的索引记录(age=22,对应 id=2):

  • 检查索引中的 reward=100000 → 满足条件 → 执行回表 :根据 id=2 到聚簇索引中取出完整行数据(id=2, age=22, reward=100000),返回给 Server 层。
步骤 4:Server 层最终校验并返回

Server 层拿到回表后的完整行,检查所有查询条件(这里只剩最终校验,通常已符合),将记录发送给客户端。

步骤 5:继续遍历剩余索引记录

存储引擎继续遍历后续 age > 20 的索引记录:

  • age=23reward=80000)→ 不满足,跳过,不回表;
  • age=24reward=100000)→ 满足,回表,返回给 Server 层;
  • age=25reward=120000)→ 不满足,跳过,不回表。

🧩 执行器与引擎的关系

  • 执行器只管"要什么数据";

  • 存储引擎负责"怎么取数据"。


⑦ 存储引擎层(Engine Layer)

InnoDB 为例(MySQL 默认引擎):

  1. 根据索引(B+ 树)定位数据页(Page)

  2. 如果数据页在 Buffer Pool(内存缓存),直接返回;

  3. 如果不在内存中,从磁盘加载到 Buffer Pool;

  4. 把对应行数据返回给执行器;

  5. 执行器拿到结果后,返回给客户端。

🧠 知识点:Buffer Pool

  • InnoDB 的数据按页(通常 16KB)为单位管理;

  • 缓存热数据,减少磁盘 I/O;

  • 类似于操作系统的页缓存机制。


🔍 三、整个执行流程图(简化版)

复制代码
客户端
   │
   ▼
连接器 → [查询缓存(已废弃)] → 解析器 → 预处理器 → 优化器 → 执行器
                                                         │
                                                         ▼
                                                 存储引擎(InnoDB)
                                                         │
                                                         ▼
                                               磁盘数据 / Buffer Pool

🚀 四、性能优化角度总结

  1. 连接层优化:使用连接池,避免频繁创建连接。

  2. SQL 优化 :查看执行计划(EXPLAIN),确认索引是否被使用。

  3. 索引优化:建立合适的联合索引、覆盖索引。

  4. 缓存优化:利用应用层缓存(Redis),减少频繁查询。

  5. 内存优化 :调大 innodb_buffer_pool_size,让更多数据命中内存。


🧭 五、完整示例总结

以语句:

复制代码
SELECT name FROM user WHERE id = 1;

整个过程如下:

  1. 客户端通过 TCP 连接到 MySQL;

  2. 连接器验证身份;

  3. SQL 进入解析器生成语法树;

  4. 预处理器验证表和列;

  5. 优化器确定使用主键索引;

  6. 执行器调用 InnoDB;

  7. InnoDB 在 Buffer Pool 查找对应页;

  8. 若页存在,直接返回;否则读磁盘;

  9. 执行器将结果返回客户端;

  10. 客户端接收并显示结果。

相关推荐
橘子海全栈攻城狮3 小时前
【源码+文档+调试讲解】基于SpringBoot + Vue的知识产权管理系统 041
java·vue.js·人工智能·spring boot·后端·安全·spring
Chloeis Syntax3 小时前
接10月12日---队列笔记
java·数据结构·笔记·队列
QT 小鲜肉3 小时前
【个人成长笔记】Qt 中 SkipEmptyParts 编译错误解决方案及版本兼容性指南
数据库·c++·笔记·qt·学习·学习方法
调试人生的显微镜3 小时前
iOS 26 文件导出全攻略,从系统限制到多工具协作实践
后端
Wang's Blog3 小时前
Linux小课堂: 系统监控与进程管理之深入解析 w、ps 与 top 命令
linux·运维·服务器
yy.y--3 小时前
Java集合操作实战:List工人管理
java
我是苏苏4 小时前
C#高级:数据库中使用SQL作分组处理4(LAG() 偏移函数)
数据库
wudl55664 小时前
股票300394(天孚通信)2025年4月20日
数据库
该用户已不存在4 小时前
这6个网站一旦知道就离不开了
前端·后端·github