Flink SQL - 基础概念详解(离线计算、实时计算、Calcite、DML)
作者:hangge | 2025-04-15 10:25
Flink 中最大的一个亮点其实就是他的 SQL 了,我们之前所接触的 Hive SQL、Spark SQL 都是基于离线数据的 SQL 计算,而 Flink 的 SQL 是可以支持实时数据计算的,这样就可以极大简化企业中实时数据分析的工作量。

(3)针对这份离线数据,通过中间这个 SQL 语句进行分组求和。最终产生的结果对应的是输出表:clicks_res 表中的内容。

一、离线计算与实时计算
1,离线计算
(1)下面图中的内容展示的是 Flink SQL 的离线计算流程,因为 Flink 不仅支持实时计算,也是支持离线计算的,所以 Flink SQL 也是可以支持离线计算的。

(2)图中左边的内容表示是用户在平台中产生的点击行为数据,这份数据是离线数据,在这里我们将这份数据定义为输入表:clicks,表中包含 3 个字段,name、time 和 url。
注意:这里的输入表 clicks 可以认为是静态表,也就是说我们在执行查询时,这个表里面的数据不会实时发生变化。
注意:针对这个离线计算任务来说,这个分组求和的 SQL 语句只需要执行一次即可。
因为离线数据已经到齐了,执行一次就可以计算出最终的结果了。
2,实时计算
(1)下面图中展示的是 Flink SQL 的实数计算流程。
- 图中左边的输入表 clicks 中的数据是实时产生的,也就意味着这个表中的数据会随着时间的变化而发生变化,所以这个表可以称之为是动态表。
- 针对这份实时产生的数据,通过中间这个 SQL 语句进行分组求和,这里的 SQL 逻辑和前面离线计算中的 SQL 逻辑是一样的,但是数据源是不一样的,一个是离线的历史数据,一个是实时新增的数据。
- 最终产生的结果对应的是输出表:clicks_res 中的内容。在这里可以发现,输出表中的数据是会动态发生变化的,因为输入表中的数据也是在一直变化的。
- 中间的这个 SQL 会触发执行多次,输入表中增加一条新数据,这个 SQL 语句就会触发执行一次,然后更新输出表中的结果数据。

(2)这个图里面的业务执行逻辑大致是这样的:
- 用户在平台中点击了一个网页,产生了第 1 条实时数据:tom,10:00:00,https://...,对应的 clicks 这个输入表中就新增了一条数据,此时会触发 SQL 的执行,SQL 会对输入表中当时的数据进行计算,将结果数据写入到输出表中,产生的结果是 Tom,1
- 接着又产生了第 2 条实时数据:Jack,10:00:00,https://...,此时也会触发 SQL 的执行,输出表中的结果会增加一条 Jack,1
- 接着又产生了第 3 条实时数据:Tom,10:00:01,https://...,此时也会触发 SQL 的执行,输出表中的结果会变成 Tom,2 和 Jack,1。因为之前 Tom 已经出现过一次了,所以这次会把之前的 Tom,1 更新为 Tom,2。jack,1 这条数据不变。
- 接着又产生了第 4 条实时数据:Jessic,10:00:03,https://...,此时也会触发 SQL 的执行,输出表中的结果会增加一条数据:Jessic,1。
- 经过这几个步骤之后,输出表中的结果最终就变成了这个样子。
(3)在这里需要注意的一点就是,Flink SQL 在执行实时计算的时候,针对这个 SQL 语句来说,数据源输入表中每新增一条数据,就会触发一次 Flink SQL 的执行,并且实时更新输出表中的结果数据。
- 此时,输入表和输出表中的数据都是动态变化的,输出表也属于动态表。
二、Flink SQL 解析引擎之 Calcite
1,基本介绍
(1)Apache Calcite 是一个开源的 SQL 解析工具,主要用来构建数据库系统的语法解析模块,不包含数据存储、数据处理等功能。
(2)Flink SQL 使用 Apache Calcite 并对其进行扩展以支持 SQL 语句的解析和验证。
(3)Apache Calcite 可以将 SQL 语句解析成抽象语法树(AST),通过操作 AST 就可以把 SQL 中表达的计算逻辑转化为具体的 Flink 代码。
2,Antlr 和 Calcite 对比
(1)目前主流的 SQL 解析引擎主要包括:Antlr 和 Calcite。
(2)Calcite 比 Antlr 更完整,Calcite 除了可以做解析还能做优化,而 Antlr 就是单纯的解析器。
- SparkSQL 使用 Antrl 实现语法解析,优化使用的是 Catalyst。
- HiveSQL 使用 Antrl 实现的语法解析,优化使用的是 Calcite。
- FlinkSQL 使用 Calcite 实现的语法解析和优化。

3,Calcite 引擎的 SQL 执行过程
(1)Parser,语法解析,这个步骤中 Calcite 会通过 Java CC 将 SQL 解析成未经校验的 AST(抽象语法树),AST 在 Calcite 中会使用 SqlNode 来表示。
(2)Validate,语法校验,这个步骤的主要作用是校验 Parser 步骤中生成的 AST 是否合法。例如:根据元数据信息验证字段、函数是否存在,SQL 语句是否合法等等,这个步骤完成之后会生成 RelNode。
(3)Optimize,语法优化,这个步骤的主要作用是优化 RelNode,并将其转化成物理计划。这里面主要会涉及到 SQL 规则优化,例如:基于规则优化(RBO) 或者 基于代价优化(CBO)。
- Optimize 这个步骤原则上来说是可选的, 通过 Validate 后的 RelNode 其实已经可以直接转化为物理计划了。但是现在的 SQL 解析器基本上都包含 Optimize 这一步,目的是为了优化 SQL 执行计划,这个步骤得到的结果就是物理计划。
(4)Execute,执行。这个步骤主要做的是将物理计划转化成可在特定平台执行的程序。例如:HiveSQL 和 FlinkSQL 都会在这个阶段将物理计划生成相应的可执行代码。
4,FlinkSQL 的执行过程
(1)SQL Parser,属于 SQL 的语法解析阶段,这里会将 Flink SQL 语句解析成 AST。
(2)SQL Validate,属于 SQL 的语法校验阶段,这里面会结合数据字典(元数据)来验证 AST 的合法性,其实就是验证 Flink SQL 语句的合法性,这里的数据字典可以认为是表的元数据信息。
(3)生成 LogicalPlan,在这里会将 AST 转换为逻辑计划。
(4)生成 Optimized LogicalPlan,在这里会基于 Calcite 的规则和 Flink 定制的规则去优化逻辑计划,然后生成优化后的逻辑计划。
(5)生成 Flink PhysicalPlan,在这里会将优化后的逻辑执行计划转换成 Flink 的物理计划。
(6)生成 Flink ExecutionPlan,在这里会将 Flink 的物理计划转换成 Flink 的执行计划,简单来说就是把 Flink 的物理计划转换成 Flink 对应的算子代码。
5,Flink SQL 中的 DML 查询语句
(1)常规查询过滤。
- 常见的 SELECT....WHERE 这种语句没有什么特殊的,就是一个普通的实时 ETL 语句,可以实现数据的清洗,过滤等操作。它产生的就是一个 Append-only 仅追加类型的实时数据流。
(2)分组聚合。
- GROUP BY 子句,这个我们前面已经用过了,主要需要注意的就是这个语句产生的结果是一个更新数据流,会涉及到数据更新。
(3)数据排序。
- ORDER BY 子句,他在流处理中很少用,意义不大,在批处理中比较常见。
- 如果想要在流处理中使用 ORDER BY,则必须在 ORDER BY 后面指定一个时间字段,表示对一段时间内的数据进行排序,因为数据流本来是无界的。
(4)数据截取。
- LIMIT 子句,他在流处理中也很少用。
(5)数据去重。
- DISTINCT,他的核心其实是通过 State 来维护之前出现过的数据,这样当有新数据过来的时候,会到 State 中判断一下,如果之前没来过则向下游输出。
(6)窗口聚合。
- 窗口聚合语句可以使用 Group Window Aggregation 或者 Windowing TVF。
- Group Window Aggregation 是 Flink1.13 版本之前提供的解决方案,这个方案在 Flink1.13 版本被标记为过时了,不建议使用了。
- 从 Flink1.13 版本开始,官方建议使用 Windowing TVF。
注意:目前 Windowing TVF 只支持流处理任务,针对批处理任务还是需要使用 Group Window Aggregation。
全部评论(0)