MySQL SQL执行流程分四层:连接器校验权限并管理会话,解析器完成词法、语法、语义分析生成解析树,优化器基于成本模型选择执行计划,执行器复检权限后调用引擎取数并组装结果。

MySQL 不会直接“执行”你写的 SQL 字符串;它先拆解、验证、重写、选路,最后才调用引擎读数据。整个过程不是线性流水线,而是一环卡住就终止——比如 分析器 发现语法错误,优化器 找不到可用索引,或 执行器 校验权限失败,都会立刻报错返回,根本不会走到后续阶段。
词法与语法分析发生在 分析器 阶段
MySQL 把 SELECT id FROM users WHERE email = 'a@b.c' 这种字符串切成一个个 Token:比如 SELECT 是关键字,id 是标识符,= 是操作符,'a@b.c' 是字符串字面量。接着按语法规则组装成一棵语法树。这一步不查表、不看索引,纯文本结构校验。
常见错误现象:
-
ERROR 1064 (42000): You have an error in your SQL syntax—— 典型的语法树构建失败,比如漏了FROM、多写了逗号、引号不闭合 - 字段名拼错但没报错?那说明它在语法上合法(比如被当成变量或别名),真正报错要等到
预处理器或执行器阶段
注意:分析器 不检查表是否存在、列是否真实、用户有没有权限——这些都留给后面环节。
优化器 决定怎么查,而不是查什么
拿到语法树后,优化器 开始生成执行计划:要不要走索引?走哪个索引?如果有多表 JOIN,先查哪张表?要不要把 WHERE 条件下推?它依赖的是统计信息(如 INFORMATION_SCHEMA.STATISTICS)、索引定义和代价模型,不是规则匹配。
关键点:
-
EXPLAIN输出的就是优化器最终选定的计划,不是“可能的计划” - 同一个 SQL,在不同数据量、不同索引、不同 MySQL 版本下,
优化器可能选完全不同的路径 - 加
FORCE INDEX或写STRAIGHT_JOIN是绕过优化器自主决策,但风险是:当数据分布变化时,人工指定的路径反而变慢
容易踩的坑:看到 type: ALL 就以为没走索引——其实可能是 优化器 认为全表扫描比索引回表更便宜(比如查 80% 的行)。
执行器 负责兜底校验和调用引擎接口
即使 优化器 生成了计划,执行器 在真正干活前还会再做一次权限检查(比如你有 SELECT 权限,但没被授权查某列),然后按计划调用存储引擎(如 InnoDB)的 API,比如 ha_innobase::index_read() 或 ha_innobase::rnd_next()。
典型行为:
- 对每行结果,
执行器会判断是否满足WHERE条件(即使索引已过滤部分数据,仍可能需要回表后二次过滤) - 遇到
ORDER BY且无合适索引时,执行器会申请 sort_buffer 做内存排序,超限时落磁盘 - 如果 SQL 涉及事务(如
UPDATE),执行器会触发InnoDB写undo log和redo log,但日志刷盘时机由引擎控制,不由执行器直接决定
这里最容易被忽略的是:执行器 层面的“执行”不等于数据落盘——它只管把指令发给引擎,至于引擎内部怎么刷日志、怎么加锁、怎么写缓冲池,执行器 不干预也不感知。


















