用户提交的 SQL 查询文本在 FE 需要经过一系列处理,最终生成一个分布式执行计划分发给各个 BE 进行计算。如下图所示,经过这么几个核心的处理流程:
-
Parser 解析,把一条文本 SQL 解析成一棵 AST 树;
-
Analyze 分析,对 AST 树进行分析,比如表是否存在等;
-
AST 树是怎么转成 Loagical Plan;
-
规则重写,基于一些规则重写 Logical Plan;
-
经过优化 Optimizer 选出最佳 Physical Plan。
本文主要分析 Anylyze 阶段做的工作, 基于StarRocks-3.4.0版本
在上一篇文章
StarRocks 查询探秘(一):SELECT语句的解析之旅
平头哥,公众号:BigData共享StarRocks 查询探秘(一):SELECT语句的解析之旅
中,剖析了 StarRocks 是如何把一条文本 SQL 解析成一颗 AST 树;本文将接着上一篇文章,分析 Analyze 阶段,该阶段主要是针对 SQL 语义进行处理,比如:判断SQL 中表/列 是否存在,函数是否存在,order by 前是否有 group by 等一系列语义检查,如下图一些语义检验例子:
Analyzer阶段的核心任务
Analyzer 阶段的核心是对 AST 进行语义分析,验证 SQL 语句是否符合数据库的语义规则**。通过 Visitor 模式结合递归遍历的方式,逐层分析 AST 的每个节点。不同的 SQL 语句类型对应不同的 Analyzer 处理逻辑,确保语义分析的针对性。
如下图所示,一条查询 SQL 对应的 QueryAnalyzer 是如何遍历 AST
对应堆栈信息
**
**
单层 SELECT 查询的语义分析
以一条简单的 SQL 查询为例,来看看 Analyzer 阶段的具体工作
SELECT uid, AVG(read_duration)FROM xx_v1WHERE time = '20250604'GROUP BY uidLIMIT 6;
Analyzer 接收上一阶段(Parser)生成的 AST,其中 stmt 就是上一个阶段构建出的 AST 抽象语法树**
逐步分析 SQL 查询的各个组成部分(SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT 等),并生成语义分析结果.
比如,在分析 WHERE 子句中,使用 AnalyzerUtils 工具类检查 WHERE 子句中的表达式是否包含以下非法内容:
- 聚合函数**(如SUM、COUNT):WHERE 子句中不允许使用聚合函数,因为它们需要在分组后计算。
- 窗口函数**(如ROW_NUMBER):WHERE 子句不支持窗口函数,因为它们依赖于查询的输出。
否则就会抛出对应的语义异常:
例如,如果在 where 后面跟个 sum(pv) 函数,就会校验抛如下错误:
**
**
**
**
多层嵌套查询的语义分析
Scope 类表示一个命名空间,命名空间包含了该作用域内对外层可见的字段信息,这样在逐级解析字段的时候才能判断该字段名是否是正确合法的。
以下面两层查询sql为例,
SELECT sum_pvFROM ( SELECT app_id, SUM(pv) AS sum_pv FROM xxx_table WHERE dt = 'xxx' GROUP BY app_id) tLIMIT 10;
分别对应的内外层 Scope 如下,
Analyzer 阶段是 SQL 查询处理中承上启下的关键环节。它通过语义分析确保 SQL 语句的正确性,并为后续的 Logical Plan 生成奠定基础。本文通过单层和嵌套查询的示例,展示了 Analyzer 的核心工作原理和 Scope 的作用。
在下一篇文章《StarRocks 查询探秘(三):AST如何转换成Logical Plan》中,我们将深入探讨AST如何转化为逻辑执行计划,敬请期待!
更多大数据干货,欢迎关注我的微信公众号—BigData共享