mysql 5.7 和 8.0 的 sql 解析阶段几乎没有性能或行为差异,均使用同一套 bison 生成的 lalr(1) 解析器;真正影响解析快慢感知的是优化器在 ast 构建后的处理逻辑升级,包括事务性数据字典、直方图统计、cte/窗口函数延迟物化及更严格的语义校验。

SELECT、INSERT 等语句切分 token、构建 AST 的过程基本一致。
真正影响“解析快慢”感知的,是 AST 构建之后的优化器行为。用户常误以为“SQL 解得更快了”,其实是优化器提前做了更多事、更少犯错,让后续执行路径变短。
Parser 本身没重写,但 AST 处理逻辑变了
5.7 和 8.0 都调用同一个 sql_yacc.yy 生成的 parser,SELECT a FROM t GROUP BY a ORDER BY a DESC 在两个版本里生成的 AST 结构几乎一样。区别在于:5.7 拿到 AST 后立刻开始规则链推导;8.0 则先查事务性数据字典、读直方图、评估索引覆盖能力,再决定是否跳过 filesort 或临时表。
- 5.7 中
EXPLAIN前要打开 .frm 文件、加载索引元数据,I/O 不可控 - 8.0 元数据全在
mysql库的 InnoDB 表里,MVCC 可并发读,延迟更低 - 8.0 默认启用
use_stat_tables = PREFERABLY,直方图统计可复用,省去运行时采样
CTE 和窗口函数改变了“解析-绑定”的粒度
5.7 不支持 WITH 或 OVER(),遇到嵌套子查询会强制展开、重复推导列名和类型,AST 构建阶段就做大量重写;8.0 把 CTE 当作独立命名空间,窗口函数的 PARTITION BY/ORDER BY 保留在 AST 节点中,不立即物化,减少解析期开销。
- 例如
WITH t AS (SELECT id, RANK() OVER (PARTITION BY dept ORDER BY salary DESC) rnk FROM emp),5.7 会在解析阶段就把RANK()展开成多层自关联子查询 - 8.0 仅保留逻辑节点,绑定和执行计划生成延后,AST 更轻、构建更快
- 但注意:
RANK、FIRST_VALUE等成了保留字,建表时用作字段名会直接报ERROR 1064
sql_mode 变更不发生在解析器,但在语法校验环节触发失败
sql_mode 不影响 token 切分或语法规则匹配,但它控制语义校验时机。8.0 移除了 NO_AUTO_CREATE_USER,且默认开启 ONLY_FULL_GROUP_BY 和 STRICT_ALL_TABLES,这些检查发生在 AST 构建完成后、优化前的“语义分析”阶段。
- 备份恢复时若含
SET sql_mode='NO_AUTO_CREATE_USER,...',MySQL 8.0 启动直接失败,报错Variable 'sql_mode' can't be set to the value of 'NO_AUTO_CREATE_USER' -
GROUP BY a后引用非聚合列b,5.7 可能只警告,8.0 直接报错(因ONLY_FULL_GROUP_BY默认启用) - 日期字面量如
'0000-00-00'在 8.0 中被拒绝,不是语法错误,而是语义校验拦截
Using temporary; Using filesort,是因为降序索引匹配、直方图辅助估算、事务性字典快速响应共同作用的结果——这些都发生在 parse 之后,但用户感知为“整条 SQL 执行更快”。











