Flink 系列第17篇:Flink Table&SQL 核心概念、原理与实战详解

1.1 核心概述

Apache Flink 提供 Table APISQL API 两套关系型 API,核心目标是统一流处理与批处理 ,是 Flink 高阶数据处理的核心能力。两套 API 底层基于 Apache Calcite 框架实现 SQL 解析、校验、优化,屏蔽了流批引擎差异。

  • Table API:基于 Java/Scala/Python 封装的流式查询 API,以 Lambda 表达式链式调用,语法贴近 SQL,兼顾代码灵活性与可读性。

  • SQL API:完全兼容标准 SQL 语法,降低大数据开发门槛,支持常规 DDL、DML、DQL 语句。

1.2 核心特性:流批统一

Flink Table&SQL 实现了用户接口层面的流批语义统一,是其最核心的优势:

  • 同一条查询语句,无需修改代码,可同时适配有界批数据 (HDFS、Hive)和无界流数据(Kafka、Pulsar);

  • 流、批模式下查询语义完全一致,计算结果逻辑统一;

  • 底层引擎自动适配执行策略,批模式启用批量优化,流模式启用实时增量计算。

二、运行环境与依赖配置

本文所有内容基于 Flink 1.17.2 版本,该版本已废弃旧版 Flink Planner,仅支持 Blink Planner 作为唯一查询优化器。

2.1 核心依赖模块解析

核心前端 API 模块,是 Table&SQL 编程的基础依赖。

核心功能

  • 提供 Table 环境入口、基础运行时能力;

  • 支持基础 SQL 解析与执行逻辑(不含优化器);

  • 实现 Table API 与 DataStream API 的双向互操作。

注意事项

  • 必须配合 Planner 模块使用,本地开发依赖 flink-table-planner-blink,集群内置 Planner;

  • 生产环境需随作业 Jar 包提交;

  • 纯 SQL 作业也必须依赖该模块提供运行时支撑。

核心后端优化执行模块,SQL 引擎的核心。

核心功能

  • 基于 Apache Calcite 实现 SQL 语法校验、逻辑优化、物理优化;

  • 生成最优查询执行计划,完成 SQL 到 Flink 算子的转换。

注意事项

  • 本地开发必须引入,生产集群已内置,依赖 scope 设为 provided

  • 与 bridge 模块对应前后端关系,缺一不可。

Table 模块通用抽象层,面向扩展开发。

核心功能:定义 Table、Catalog、UDF 通用抽象接口,提供自定义 Connector、Format、UDF 的 SPI 扩展点。

注意事项

  • 普通业务开发无需主动依赖,仅自定义扩展场景需要;

  • 生产环境需随 Jar 提交,版本必须与 Flink 核心版本严格一致。

2.2 Maven 依赖配置

2.2.1 Java 开发依赖

xml 复制代码
<properties>
    <flink.version>1.17.2</flink.version>
    <scala.binary.version>2.12</scala.binary.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-api-java-bridge_${scala.binary.version}</artifactId>
    <version>${flink.version}</version>
  </dependency>
  
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-planner-blink_${scala.binary.version}</artifactId>
    <version>${flink.version}</version>
    <scope>provided</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
    <version>${flink.version}</version>
    <scope>provided</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-common</artifactId>
    <version>${flink.version}</version>
  </dependency>
</dependencies>

2.2.2 Scala 开发依赖

xml 复制代码
<properties>
    <flink.version>1.17.2</flink.version>
    <scala.binary.version>2.12</scala.binary.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-api-scala-bridge_${scala.binary.version}</artifactId>
    <version>${flink.version}</version>
  </dependency>
  
  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-planner-blink_${scala.binary.version}</artifactId>
    <version>${flink.version}</version>
    <scope>provided</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
    <version>${flink.version}</version>
    <scope>provided</scope>
  </dependency>

  <dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-table-common</artifactId>
    <version>${flink.version}</version>
  </dependency>
</dependencies>

三、核心代码结构与常用 API

3.1 标准代码执行流程

Flink Table&amp;SQL 作业遵循固定开发模板,流程清晰统一:

  1. 通过 EnvironmentSettings 配置执行模式(流/批);

  2. 创建 TableEnvironment 执行环境;

  3. 定义数据源表、数据汇表;

  4. 通过 Table API/SQL API 编写计算逻辑;

  5. 执行写入,触发作业运行。

java 复制代码
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
import org.apache.flink.table.api.Table;
import org.apache.flink.table.api.TableResult;

// 1. 配置执行环境(流模式/批模式)
EnvironmentSettings settings = EnvironmentSettings.newInstance()
    .inStreamingMode() // 实时流任务
    //.inBatchMode() // 离线批任务
    .build();

// 2. 创建Table执行上下文
TableEnvironment tableEnv = TableEnvironment.create(settings);

// 3. 注册输入表
tableEnv.executeSql("CREATE TEMPORARY TABLE table1 ... WITH ( 'connector' = ... )");
// 4. 注册输出表
tableEnv.executeSql("CREATE TEMPORARY TABLE outputTable ... WITH ( 'connector' = ... )");

// 5. Table API 查询计算
Table table2 = tableEnv.from("table1").select(...);
// 6. SQL API 查询计算
Table table3 = tableEnv.sqlQuery("SELECT ... FROM table1 ... ");

// 7. 写入结果,执行作业
TableResult tableResult = table2.executeInsert("outputTable");

3.2 核心工具类详解

3.2.1 EnvironmentSettings

Table 环境配置类,用于定义作业核心运行模式:

  • 指定执行模式:inStreamingMode() 流处理、inBatchMode() 批处理;

  • Flink 1.13+ 废弃 Planner 选择配置,默认唯一使用 Blink Planner;

  • 支持绑定全局 Configuration 配置。

3.2.2 TableEnvironment / StreamTableEnvironment

Table&amp;SQL 所有操作的入口上下文,管理作业全部运行时资源:

  • 元数据管理:Catalog、数据库、表、视图;

  • 函数管理:注册/删除临时 UDF、系统级 UDF;

  • SQL 执行:执行 DDL、DML、DQL 语句;

  • 流批互通:支持 Table 与 DataStream 双向转换。

核心常用方法

  • 表管理:createTemporaryView()from()dropTemporaryTable()

  • SQL 执行:executeSql()(执行DDL/DML)、sqlQuery()(查询返回Table);

  • UDF 管理:createTemporaryFunction()createTemporarySystemFunction()

关键区别StreamTableEnvironment 绑定 DataStream 执行环境,共享 Checkpoint、水位线、时间语义,生产流作业优先使用

3.2.3 Configuration

Flink 全局配置中心,线程安全,以键值对形式统一管理所有运行时参数,贯穿整个执行栈,支持并行度、Checkpoint、状态TTL、Table 优化参数等全局配置。

3.3 生产级环境模板

3.3.1 流式作业模板(生产首选)

适用于 Kafka、Pulsar 等实时数据源,默认开启容错、状态管理、Checkpoint 机制。

java 复制代码
import org.apache.flink.configuration.Configuration;
import org.apache.flink.configuration.CoreOptions;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
import org.apache.flink.table.api.config.ExecutionConfigOptions;
import org.apache.flink.table.api.config.TableConfigOptions;

import java.time.Duration;

public class StreamingTableEnvTemplate {
    public static void main(String[] args) {
        // 1. 全局配置初始化
        Configuration config = new Configuration();
        config.set(CoreOptions.DEFAULT_PARALLELISM, 4);
        config.set(CoreOptions.CHECK_LEAKED_CLASSLOADER, false);

        // 2. Checkpoint 核心容错配置
        config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_INTERVAL, Duration.ofSeconds(30));
        config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_TIMEOUT, Duration.ofMinutes(10));
        config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_MIN_PAUSE, Duration.ofSeconds(5));
        config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_MAX_CONCURRENT, 1);
        config.set(ExecutionConfigOptions.TABLE_EXEC_CHECKPOINTING_EXTERNALIZED_CHECKPOINT,
                ExecutionConfigOptions.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);

        // 3. 状态与执行优化配置
        config.set(TableConfigOptions.TABLE_EXEC_RESOURCE_DEFAULT_PARALLELISM, 4);
        config.set(TableConfigOptions.TABLE_EXEC_STATE_TTL, Duration.ofHours(24));
        config.set(TableConfigOptions.TABLE_EXEC_SOURCE_IDLE_TIMEOUT, Duration.ofMinutes(5));

        // 4. 创建流执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(config);

        // 5. 创建Table环境,绑定流环境
        EnvironmentSettings settings = EnvironmentSettings.newInstance()
                .inStreamingMode()
                .withConfiguration(config)
                .build();
        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, settings);
    }
}

3.3.2 批量作业模板

适用于 Hive、HDFS、JDBC 离线数据源,无需 Checkpoint 和状态 TTL,自动启用批量执行优化。

java 复制代码
import org.apache.flink.configuration.Configuration;
import org.apache.flink.configuration.CoreOptions;
import org.apache.flink.table.api.EnvironmentSettings;
import org.apache.flink.table.api.TableEnvironment;
import org.apache.flink.table.api.config.TableConfigOptions;

public class BatchTableEnvTemplate {
    public static void main(String[] args) {
        Configuration config = new Configuration();
        config.set(CoreOptions.DEFAULT_PARALLELISM, 8);
        config.set(TableConfigOptions.TABLE_EXEC_RESOURCE_DEFAULT_PARALLELISM, 8);
        config.set(TableConfigOptions.TABLE_EXEC_EMIT_EARLY_FIRE_ENABLED, false);

        EnvironmentSettings settings = EnvironmentSettings.newInstance()
                .inBatchMode()
                .withConfiguration(config)
                .build();

        TableEnvironment tableEnv = TableEnvironment.create(settings);
    }
}

四、动态表核心概念

4.1 动态表定义

动态表(Dynamic Table)是 Flink 对流式无限数据的逻辑表抽象,是 Table&amp;SQL API 的核心底层概念:

  • 本质是持续变化的逻辑表,无固定数据快照,数据随流实时更新;

  • 任意时刻均可像静态批表一样执行查询;

  • 所有 Flink SQL 查询都是基于动态表的持续增量计算

4.2 三层命名空间规则

Flink 所有表、视图遵循 Catalog.数据库.表名 三层命名规范:[catalog_name.][database_name.]table_name

默认命名空间

  • 默认 Catalog:default_catalog

  • 默认数据库:default_database

4.3 动态表分类

4.3.1 按数据来源分类

  1. 物理表(Physical Table)

    • 通过 CREATE TABLE 语句创建,与外部存储系统(Kafka、MySQL、Hive)绑定;

    • 数据真实存储在外部系统,Flink 仅维护 Schema 元数据;

    • 拥有固定字段结构,通过 Connector 完成序列化/反序列化。

  2. 逻辑视图(View)

    • 通过 CREATE VIEW ... AS SELECT 创建,仅存储查询逻辑,不存储任何数据

    • 每次被引用都会重新执行底层查询;

    • 用于简化复杂查询、逻辑分层,推荐使用临时视图。

4.3.2 按生命周期分类

  1. 临时表/视图(Temporary)

    • 仅当前 Session 会话有效,作业重启后失效;

    • 内存存储,优先级高于同名持久化表;

    • 适合临时测试、作业内逻辑封装。

  2. 持久化表(Persistent)

    • 元数据存储在 Catalog 中,跨会话、跨作业有效;

    • 作业重启后可直接复用表定义,无需重复建表;

    • 生产环境核心使用方式,依赖 HiveCatalog 等持久化元数据组件。

Flink 无传统数据库的物化视图 ,所有视图均为逻辑视图,不缓存计算结果。但 Flink 通过三大机制天然实现动态物化视图语义

  1. 持续计算:基于流式数据实时增量更新计算结果;

  2. 状态管理:自动维护聚合、Join 等算子的计算状态;

  3. 外部持久化:通过 Sink 将结果写入外部存储,实现结果落地复用。

4.5 Table 与 DataStream 互转

生产环境较少使用,核心适用场景:SQL 负责批量计算,DataStream 负责自定义复杂逻辑(报警、特殊处理)

java 复制代码
// 场景:统计补贴券发放总金额,超1w触发报警
// 1. 定义数据源表
String createTableSql = "CREATE TABLE source_table (\n"
        + "    id BIGINT,\n"
        + "    money BIGINT,\n"
        + "    row_time AS cast(CURRENT_TIMESTAMP as timestamp_LTZ(3)),\n"
        + "    WATERMARK FOR row_time AS row_time - INTERVAL '5' SECOND\n"
        + ") WITH (\n"
        + "  'connector' = 'datagen',\n"
        + "  'rows-per-second' = '1'\n"
        + ")";

// 2. SQL 累计聚合计算
String querySql = "SELECT UNIX_TIMESTAMP(CAST(window_end AS STRING)) * 1000 as window_end, \n"
        + "      window_start, \n"
        + "      sum(money) as sum_money\n"
        + "FROM TABLE(CUMULATE(\n"
        + "         TABLE source_table\n"
        + "         , DESCRIPTOR(row_time)\n"
        + "         , INTERVAL '5' SECOND\n"
        + "         , INTERVAL '1' DAY))\n"
        + "GROUP BY window_start, window_end";

tableEnv.executeSql(createTableSql);
Table resultTable = tableEnv.sqlQuery(querySql);

// 3. Table 转 DataStream,自定义报警逻辑
tableEnv.toDataStream(resultTable, Row.class)
        .flatMap((Row value, Collector<Object> out) -> {
            long totalMoney = Long.parseLong(String.valueOf(value.getField("sum_money")));
            if (totalMoney > 10000L) {
                System.out.println("报警:补贴券发放总金额超过1w,当前金额:" + totalMoney);
            }
        });

五、Catalog 元数据管理

5.1 Catalog 核心作用

Catalog 是 FlinkSQL 的元数据管理中心,统一管理数据库、表、视图、函数、分区等所有元数据,核心价值:

  • 解耦计算与元数据:表定义、Schema、连接器配置与代码分离,SQL 更简洁通用;

  • 跨会话持久化:持久化 Catalog 可实现元数据跨作业、跨重启复用;

  • 多租户隔离:多 Catalog、多数据库实现业务资源逻辑隔离;

  • 外部元数据复用:直接对接 Hive、MySQL 元数据,无需重复建表。

5.2.1 GenericInMemoryCatalog(默认)

  • 基于内存实现,元数据仅当前 Session 有效,作业停止即丢失;

  • 区分大小写,仅适用于本地测试、临时查询;

  • 无需手动配置,系统默认启用。

5.2.2 JdbcCatalog

  • 通过 JDBC 协议对接关系型数据库,目前仅支持 Postgres;

  • 可直接映射数据库表为 Flink 表,复用存量元数据。

5.2.3 HiveCatalog(生产标配)

  • 对接 Hive Metastore,实现元数据持久化存储;

  • 支持读写 Hive 表、分区、函数,完美适配数仓体系;

  • 元数据默认小写存储,生产环境必备。

java 复制代码
// 代码注册HiveCatalog
String name = "myhive";
String defaultDatabase = "mydatabase";
String hiveConfDir = "/opt/hive-conf";

HiveCatalog hiveCatalog = new HiveCatalog(name, defaultDatabase, hiveConfDir);
tableEnv.registerCatalog("myhive", hiveCatalog);
tableEnv.useCatalog("myhive");

5.3 Catalog 常用 SQL 操作

sql 复制代码
-- 1. 创建各类Catalog
CREATE CATALOG hive_catalog WITH (
    'type' = 'hive',
    'hive-conf-dir' = '/path/to/hive/conf',
    'hadoop-conf-dir' = '/path/to/hadoop/conf',
    'default-database' = 'default'
);

CREATE CATALOG jdbc_catalog WITH (
    'type' = 'jdbc',
    'default-database' = 'business_db',
    'username' = 'flink_user',
    'password' = 'flink_password',
    'base-url' = 'jdbc:mysql://localhost:3306'
);

-- 2. 查看与切换Catalog
SHOW CATALOGS;
USE CATALOG hive_catalog;
SHOW CURRENT CATALOG;

-- 3. 跨Catalog操作表
CREATE TABLE hive_catalog.dim_db.user_dim (
  user_id BIGINT,
  user_name STRING
) WITH (...);

Flink Table&amp;SQL 拥有独立的类型系统,兼容 SQL 标准,同时适配 JVM 语言类型,包含原子类型、复合类型、自定义类型三大类,支持空值判定、物理类型映射,适配序列化与存储场景。

6.1 原子数据类型

6.1.1 数值类型

类型 字节数 说明 对应Java类型
TINYINT 1 字节整数,范围 -128~127 Byte
SMALLINT 2 短整数,范围 -32768~32767 Short
INT/INTEGER 4 常用整数 Integer
BIGINT 8 长整数 Long
FLOAT 4 单精度浮点,有损精度 Float
DOUBLE 8 双精度浮点,有损精度 Double
DECIMAL(p,s)/NUMERIC(p,s) 可变 高精度无损小数,p总位数(1-38),s小数位数(0-p) BigDecimal

6.1.2 字符类型

类型 说明 备注
CHAR(n) 定长字符串,空格填充 n默认1,最大2147483647
VARCHAR(n) 可变长度字符串 n默认1
STRING 超长可变字符串 等价于 VARCHAR(2147483647)

6.1.3 时间类型

类型 说明 精度规则
DATE 年月日日期,无时区 无精度
TIME(p) 时分秒时间,无时区 p固定为0
TIMESTAMP(p) 时间戳,无时区 p固定为3(毫秒),默认6
TIMESTAMP_LTZ(p) 带本地时区时间戳 时区由全局参数配置
INTERVAL 时间间隔类型 支持 YEAR TO MONTH、DAY TO SECOND

6.1.4 其他基础类型

  • BOOLEAN:布尔类型,true/false

  • BINARY(n):定长二进制字节数组

  • VARBINARY(n)/BYTES:可变二进制数组,BYTES 等价于 VARBINARY(2147483647)

  • RAW:原始类型,保留对象原始结构,仅序列化传输,需指定Java类型与序列化器

  • NULL:空值类型

6.2 复合数据类型

复合类型序列化开销高于原子类型,性能关键路径需谨慎使用。

6.2.1 ARRAY 数组类型

存储同类型元素集合,最大长度 2147483647,索引从1开始。

sql 复制代码
ARRAY<INT>
ARRAY<STRING>
-- 常用函数
SELECT tags[1], CARDINALITY(tags) FROM events;

6.2.2 MAP 映射类型

键值对集合,同组 key/value 类型统一。

sql 复制代码
MAP<STRING, INT>
-- 常用操作
SELECT config['timeout'], MAP_KEYS(config) FROM settings;

6.2.3 MULTISET 多重集合

支持元素重复的集合类型,对应 Java List。

6.2.4 ROW 行类型

微型结构化表,包含多个命名字段,对应 Flink Row 对象,支持嵌套。

sql 复制代码
ROW<name STRING, age INT, score DOUBLE>
-- 嵌套字段访问
SELECT address.city FROM users;

6.3 自定义数据类型

6.3.1 POJO 结构化自定义类型

Flink 可自动识别符合规范的 POJO,支持通过注解指定字段数据类型。

java 复制代码
public class User {
    public int age;
    public String name;
    // 注解指定高精度小数类型
    public @DataTypeHint("DECIMAL(10, 2)") BigDecimal totalBalance;
}

// 自定义UDF使用POJO类型
public class UserScalarFunction extends ScalarFunction {
    public User eval(long i) {
        User user = new User();
        user.age = (int) i;
        user.name = "test";
        user.totalBalance = new BigDecimal(1.1d);
        return user;
    }
}

6.3.2 UDT 完全自定义原生类型

通过继承 UserDefinedType 实现完全自定义类型,适配地理坐标、IP 等特殊业务类型,需手动实现序列化与注册逻辑。

七、总结

  1. Flink Table&amp;SQL 核心价值是流批统一,一套代码适配流、批双场景,大幅降低开发成本;

  2. 运行环境依赖分为前端 API 模块与后端优化器模块,生产环境需严格区分依赖 scope;

  3. 动态表是流式 SQL 的核心原理,通过持续增量计算+状态管理实现动态物化视图效果;

  4. Catalog 实现元数据持久化与统一管理,HiveCatalog 是生产环境标配;

  5. Flink 类型体系完善,原子类型高效稳定,复合类型灵活适配复杂场景,POJO 自定义类型适配个性化业务。

相关推荐
Irene19911 小时前
SQL 中的大小写规则总结:关键字、函数名不区分大小写(建议大写),字符串值、日期格式符严格区分大小写
sql·大小写规范
我是发哥哈2 小时前
主流AI视频生成方案商用化能力横向评测
大数据·人工智能·学习·机器学习·chatgpt·音视频
素玥2 小时前
大数据专业实践作业
大数据
武子康2 小时前
大数据-278 Spark MLib-GBDT梯度提升决策树详解:从原理到实战案例
大数据·后端·spark
数智化精益手记局2 小时前
什么是仓库安灯管理系统?一文讲清仓库安灯管理系统的核心概念
大数据·网络·人工智能·安全·精益工程
aq55356002 小时前
Chrome如何重塑Web标准的未来
大数据·elasticsearch
不剪发的Tony老师2 小时前
DBcooper:一款面向开发者的现代数据库客户端
数据库·sql
数智化精益手记局2 小时前
仓库安灯管理系统的异常响应机制:破解仓库安灯管理系统的跨部门协同难题
大数据·数据结构·人工智能·制造·精益工程
卢傢蕊3 小时前
FastDFS 分布式存储
分布式·fastdfs