MySQL的SQL解析发生在Server层第一阶段,仅做语法合法性判断并生成Parse Tree,不校验表结构或权限,核心由Bison基于sql_yacc.yy生成的LALR(1)分析器完成。

MySQL 的 SQL 解析发生在哪个阶段
SQL 语句进入 MySQL 后,解析(parsing)是 Server 层的第一道处理环节,在执行器调用存储引擎前完成。它不涉及表结构校验或权限检查,只做语法合法性判断和初步结构化——也就是把字符串 SELECT * FROM users WHERE id = 1 拆成「查询类型」「目标表」「条件表达式」等内部节点。
parse_yacc.yy 是核心,但你改不了它
MySQL 使用 GNU Bison 从 sql/sql_yacc.yy(旧版本)或 sql/parse_tree_nodes.h + 自动生成的 sql/sql_yacc.cc(8.0+)构建 LALR(1) 语法分析器。这意味着:
- 所有合法 SQL 形式都由该文法定义,比如
INSERT ... ON DUPLICATE KEY UPDATE能被识别,是因为文法规则里明确写了insert_statement: INSERT ... on_duplicate_key_clause - 你无法通过配置或插件绕过或替换这个解析器;想支持新语法(如自定义函数关键字),必须修改
.yy文件并重新编译 MySQL - 错误信息如
ERROR 1064 (42000): You have an error in your SQL syntax就来自 Bison 的报错回调,位置通常精确到 token 序号,但不包含列号
解析结果是 Parse Tree,不是 AST
MySQL 构建的是「解析树(Parse Tree)」,而非通用编译器意义上的抽象语法树(AST)。它的节点更贴近原始语法结构,例如:
SELECT a+b FROM t WHERE c > 10
会被拆为:
-
SELECT_LEX节点含item_list(存a+b)、table_list(存t)、where(存c > 10) -
a+b是Item_func_plus实例,c > 10是Item_func_gt,它们都继承自Item,但此时尚未绑定字段类型或 NULL 属性 - 这个树后续会传给语义分析器(如
SELECT_LEX::prepare())做字段名解析、类型推导、别名展开等——那才是真正的“查表”动作开始的地方
常见解析失败原因和定位方法
很多看似「语义错误」的问题其实在解析阶段就卡住了,比如:
- 使用了保留字作别名却没加反引号:
SELECT name AS order FROM t→order是保留字,Bison 规则中它被定义为关键字 token,直接匹配失败 - 字符串未闭合:
SELECT 'hello FROM t→ 解析器一直等待下一个',直到缓冲区满或换行,报错位置常在末尾而非缺失处 - JSON 字面量写成
{a: 1}(缺少引号)→ MySQL 8.0 只接受标准 JSON 格式{"a": 1},否则解析器不认识{后跟标识符的组合 - 客户端发送了多语句但未启用
CLIENT_MULTI_STATEMENTS标志 → 即使 SQL 本身合法,MySQL Server 也会在解析第一句后丢弃剩余部分,不报错也不提示
调试时可开启 --debug=d,parser 启动 mysqld,它会在错误日志中输出 token 流和归约步骤,但输出极冗长,仅适合确认是否真的卡在某条规则上。










