返回 导航

大数据

hangge.com

Flink SQL - 表类型概念详解(静态表、动态表、版本表、连续查询)

作者:hangge | 2025-04-18 08:37

一、表类型介绍

1,基本介绍

(1)Flink 中的表从全局层面进行划分,可以分为静态表(Static Table)和动态表(Dynamic Table)。
  • 其中动态表里面中还包括一种特殊的表:时态表(Temporal Table)。时态表是在 Flink1.11 版本中引入的,只在 Blink 引擎中支持。

(2)从 Flink1.12 版本开始,官方移除了时态表的概念,增加了版本表(Versioned Table),版本表其实和之前的时态表是类似的。
  • 版本表可以简单理解为是在动态表中定义了主键和事件时间属性,有了时间属性之后,他就可以记录数据的历史变化情况了,也可以支持用户访问某个时刻的历史数据。
  • 某一些动态表中也包含了数据的历史变化情况,但是没有定义主键,不属于版本表,这个时候可以借助于时态表函数实现访问某个时刻的历史数据。

2,静态表

(1)静态表,对应的都是离线数据,也就意味着表中的数据不会随着时间实时变化。
  • 例如:我们前面在 BatchMode(批处理)模式下使用 filesysterm 定义的表,这种表就是静态表(点击查看)。

(2)静态表中的数据也可能会发生变化,只不过不会随着时间实时变化。
  • 例如 Hive 中的表,这些表都属于静态表,但是这些静态表里面的数据也是会发生变化的,一般会按照小时级别、或者天级别新增一部分数据,但是他不会随着时间实时变化。

3,动态表

(1)动态表,对应的是实时数据,也就意味着表中的数据会随着时间实时变化。
  • 例如:我们前面在 StreamingMode 模式下使用 Kafka 定义的表,这种表就是动态表(点击查看)。

(2)动态表是 Flink SQL 能够支持流数据处理的核心概念,如果没有动态表,Flink SQL 是无法支持对流数据进行处理的。
  • 下图显示了实时数据流如何转换为动态表。图中左边代表的是源源不断产生的实时数据流,基于这份数据流,我们定义了一个输入表:clicksclicks 这个表里面的数据会随着时间实时变化,所以 clicks 这个表就是动态表。

4,版本表

(1)版本表其实就是一种特殊类型的动态表,它会记住每个键的历史值。可以在具有主键和事件时间属性的动态表上定义版本表。
  • 版本表其实就相当于 Retract 流对应的表,他里面会记录数据的变化情况。
  • 版本表和我们在 Hive 中构建的拉链表是类似的,通过 Hive 构建的拉链表也是可以记录数据的历史变化情况的。
提示:版本表主要是在实现 JOIN 需求的时候使用。

(2)下图里面可以看出来数据在不同时刻的变化情况,这个图中的数据对应的表就可以称之为“版本表”。
  • chanlog kind:表示数据的行为,包括 +INSERT-UPDATE_BEFORE+UPDATE_AFTER -DELETE
  • update_timeproduct_idproduct_nameprice 这几个表示是具体的业务字段。
  • 针对版本表中的数据,在不同时间点查询数据,可以获取到不同的结果。
    • 当我们在 11 点的时候进行查询,可以获取到商品 p_001 的价格为 11.11,商品 p_002 的价格为 23.11
    • 当我们在 13 点进行查询的时候,可以获取到商品 p_001 的价格为 12.99,商品 p_002 的价格为 19.99
    • 当我们在 19 点进行查询的时候,就获取不到商品 p_001 的信息了,因为这条商品数据在 18 点的时候就被删掉了。

(3)版本表的建表语句和普通的动态表类似,主要是需要定义主键和事件时间字段。以下面 SQL 语句为例:
  • 通过 PRIMARY KEY (product_id) NOT ENFORCED 指定 product_id 字段为主键字段,NOT ENFORCED 表示不开启强校验,默认都会这样指定。
  • 通过 watermark 定义事件时间,当然前提是需要在表中先定义一个时间字段。
    • 其中 FOR 后面指定的 update_time 直接使用表中的时间字段即可,AS 后面可以指定一个表达式,表示允许数据的乱序时间。在这先了解一下这种定义格式,后面我们会详细分析 watermarkFlink SQL 中的使用。
CREATE TABLE products (
    update_time TIMESTAMP(3),
    product_id STRING,
    product_name STRING,
    price DECIMAL(32, 2),
    -- (1) 定义主键
    PRIMARY KEY (product_id) NOT ENFORCED,
    -- (2) 通过 watermark 定义事件时间
    WATERMARK FOR update_time AS update_time
) WITH (...);

5,时态表函数

(1)时态表函数可以支持访问动态表中指定时间点的数据版本,这里所说的动态表属于仅追加类型的。
  • 与版本表不同,时态表函数只能在仅追加表上定义
(2)时态表函数不能通过 SQL DDL 定义,需要通过 Table API 注册。
(3)时态表函数的主要应用场景也是在实现 JOIN 需求时使用。

二、动态表 + 连续查询

1,什么是连续查询?

(1)连续查询这个概念是相对于一次查询而言的。
  • 针对离线数据,也就是静态表中的数据,我们定义一个 SQL 计算逻辑,这个 SQL 计算逻辑就只会执行一次,执行一次就结束了,这种不属于连续查询。
  • 针对动态表中的数据,我们定义一个 SQL 计算逻辑,只要动态表中的数据发生了变化,这个 SQL 计算逻辑就会触发执行。动态表中的数据会随着时间实时变化,对应的这个 SQL 计算逻辑也会随着时间实时触发执行。这种情况下,针对这个 SQL 计算逻辑的多次执行,我们就可以称之为连续查询。

(2)连续查询其实就是不断消费动态输入表中的数据进行计算,进而不断更新动态输出表中的结果数据。
  • 此时的输入表和输出表都是动态表。
  • 当动态输入表中的数据发生了变化之后就会触发 SQL 计算逻辑的执行,这样就可以保证 SQL 计算逻辑产生的结果是最新的。

(3)在一个实时数据流中,使用 Flink SQL 进行计算,并且生成结果,这个执行流程中大致会涉及三个步骤:
  • 第一步:首先将实时数据流转换为动态输入表,这里的转换操作其实就是基于实时数据流定义一个动态表。
  • 第二步:在动态输入表上定义一个 SQL 计算逻辑,其实就是定义一个连续查询,连续查询在执行的时候会用到 State 来维护一些中间结果数据,连续查询会生成一个动态输出表。
  • 第三步:动态输出表被转换为数据流最终写出去。

2,连续查询案例一

(1)下面是一个简单的分组聚合需求,只不过是应用在流计算场景中。

(2)在这个流计算场景中,输入表:clicks ,其实就是一个动态表了,最开始这个表中的数据是空的。
  • 当第一条数据进入 clicks 表里面的时候,这个 Flink SQL 语句就会触发执行了,或者说是连续查询触发执行了,针对第一条数据计算的结果是(Tom,1),然后把结果插入到结果表中。
  • 当第二条数据进入 clicks 表里面的时候,连续查询会继续触发执行,得到结果(Jack,1),并把这个结果插入到结果表中。
  • 当第三条数据进入 clicks 表里面的时候,连续查询会继续触发执行,此时会得到结果(Tom,2),因为 Tom 这条数据已经出现过一次了,所以到现在为止出现了两次,此时会把这个结果更新到结果表中,把结果表中的(Tom,1)更新为(Tom,2)
  • 当第四条数据进入 clicks 表里面的时候,连续查询会继续触发执行,得到结果(Jessic,1),并把这个结果插入到结果表中。
  • 所以目前结果表中的数据是(Tom,2)(Jack,1)(Jessic,1)

(3)在这个 Flink SQL 计算逻辑下,结果表中的数据会产生两种行为:新增和更新。

3,连续查询案例二

(1)这个案例和前面的第一个案例有点类似,不过有一点区别是 Flink SQL 的计算逻辑不一样。
  • 这里的 Flink SQL 计算逻辑虽然也是实现分组聚合统计,但是在分组的时候,除了根据 name 字段分组,还会根据时间分组。
  • 这个 Flink SQL 的计算逻辑其实和 Flink 中的滚动窗口聚合需求是一样的,根据时间划分窗口,然后针对窗口内的数据进行分组聚合统计。
  • 通过这个 Flink SQL 可以看出来,此时的窗口大小粒度是小时,也就是说每一个小时执行一次分组聚合的操作。

(2)通过图中的输入表可知,在 [10:00:00~11:00:0) 这个时间区间内的数据有 3 条(这是一个左闭右开的区间),[11:00:00~12:00:00) 这个时间区间内的数据有 3 条,[12:00:00~13:00:00) 这个时间区间内的数据有 3 条。
  • 假设这个 Flink SQL 任务是 10:00:00 开始执行的,当达到 10:59:59 这个时间点的时候,正好满足滚动窗口的时间间隔,这个 Flink SQL 就会触发执行了,或者说连续查询触发执行了,此时计算的结果是 (Tom,11:00:00,2) (Jack,11:00:00,1),然后把结果插入到结果表中。
注意:结果表中的 endTime 字段的值取的是时间窗口的结束时间,因为现在时间窗口的大小是 1 小时,针对 [10:00:00~11:00:00)这个左闭右开的时间窗口而言,开始时间是 10:00:00,结束时间是 11:00:00
注意:这个时候不会更新之前结果表中的数据,因为现在有一个时间字段,所以这些数据都是新增的。

(3)在这个 Flink SQL 计算逻辑下,结果表中的数据只会产生一种行为:新增,因为此时涉及了基于时间窗口的分组聚合,最终的结果数据都是和时间有关系的,时间是递增的,所以结果也都是新增的。
  • 针对连续查询的输出结果数据而言,可能是新增,也可能是更新。所以,连续查询的输出结果可以认为是一个 changlog 数据流。
  • changlog 的概念其实类似于 MySQL 中的 binlog 日志,里面会包含 INSERTUPDATEDELETE 这些形式的数据,通过这些形式的数据来描述实时计算技术对于动态表中数据的变更操作。
评论

全部评论(0)

回到顶部