主键表
本文将为您介绍Fluss的主键表。
基本概念
Fluss中的主键表需要确保指定主键的唯一性,并支持INSERT
、UPDATE
和DELETE
操作。
例如,以下 Flink SQL 语句创建了一个主键表,其中shop_id
、user_id
和ds
被定义为主键,并将数据分布到4个分桶中。
CREATE TABLE pk_table (
shop_id BIGINT,
user_id BIGINT,
num_orders INT,
total_amount INT,
ds STRING
PRIMARY KEY (shop_id,user_id,ds) NOT ENFORCED
) WITH (
'bucket.num' = '4'
);
当多条具有相同主键的数据被写入时,会根据处理时间,默认保留最后一条写入的数据。更多写入策略请参见Merge Engines。
如果是分区表 ,主键必须包含所有分区键字段(例如分区键是ds,则ds必须为主键之一)。因为数据是按分区键划分,且保证每个分区内数据的主键唯一性可以维护,避免出现不同分区内有相同主键的数据。
数据分桶
对于主键表,Fluss 根据每条记录的分桶键(bucket key)的哈希值决定其归属的分桶。
分桶键必须是主键的一部分(不包括分区键)。
例如主键为shop_id,user_id,ds。分区键为ds。则分桶键可以为
'bucket.key' = 'user_id,shop_id'
、'bucket.key' = 'user_id'
或'bucket.key' = 'shop_id'
。若未显式指定分桶键,则默认使用主键中除去分区键的部分作为分桶键。
例如主键为shop_id、user_id,ds。分区键为ds。未指定分桶键,则分桶键为
'bucket.key' = 'user_id,shop_id'
。相同哈希值的数据会被分配到同一个分桶中,便于并行处理和负载均衡。
更多详情请参见数据分桶。
部分列更新
对于主键表,Fluss 支持部分列更新(Partial Update),您可以只写入部分列来对数据进行逐步更新,并最终得到完整的数据。需要注意的是,要写入的列必须包含主键列。
CREATE TABLE T (
k INT,
v1 DOUBLE,
v2 STRING,
PRIMARY KEY (k) NOT ENFORCED
);
可以分别写入部分列数据,但必须包含主键列,如下图所示
Merge Engines
Fluss中的合并引擎(Merge Engine)是一个核心组件,旨在高效处理和整合主键表的数据更新操作。它为用户提供了灵活性,允许定义如何将新进数据记录与具有相同主键的现有记录进行合并。此外,用户还可以指定不同的合并引擎,以根据具体使用场景自定义合并行为。
以下是支持的合并引擎:
当新记录与现有记录具有相同主键时,保留最新的记录(依据处理时间,最后写入的记录)。
与默认策略相反,该引擎会保留最早的记录(依据处理时间,即最先写入的记录)。
适用于需要保留初始数据状态的场景。
支持基于版本号的合并逻辑。
用户可以根据记录中的版本号字段来决定保留哪个版本的数据。
适用于需要管理数据版本化或增量更新的场景。
Changelog 生成
Fluss 会记录主键表中数据增删与更新的变更数据,即 changelog,下游消费者可以直接消费 changelog 来得到表的变更。
如果写入 Fluss 主键表的数据依次为插入两条数据(1, 2.0, 'apple')
,(1, 4.0, 'banana')
, 再删除一条数据(1, 4.0, 'banana')
,则将产生如下的变更数据:
+I(1, 2.0, 'apple')
-U(1, 2.0, 'apple')
+U(1, 4.0, 'banana')
-D(1, 4.0, 'banana')
主键表的读取与查询
读取
对于主键表,默认的读取方式是全量快照(Full Snapshot)加上增量数据(Incremental Data):
首先消费表的快照数据(Snapshot Data)。
然后消费表的变更日志数据(Changelog Data)。
此外,也可以仅消费表的变更日志数据。更多详情请参见读取数据。
主键查询
Fluss 主键表支持通过主键进行数据查询。如果指定的主键存在于 Fluss 中,查询将返回唯一的一行数据。这种查询方式通常用于 Flink Lookup Join 场景。
前缀查询
Fluss 主键表还支持基于主键前缀子集的前缀查询。与主键查询不同,前缀查询会根据主键的前缀扫描数据,并可能返回多行结果。这种查询方式通常用于 Flink Prefix Lookup Join 场景。