本文介绍 DLF Paimon Append(非主键)表的基本特性与功能。
快速决策
类别 | 场景 | 配置建议 |
分桶方式 | 海量追加、不关心顺序与点查(如日志、埋点、ODS 明细等)。 | 无分桶(默认) |
同 key 数据流读顺序需要和写入顺序相同 | 固定分桶 | |
需要按 key 做数据裁剪,或者需要 Spark 的 bucketed join 优化 |
| |
行级更新删除 | 通过 Spark 对 Append 表轻量化做 DELETE / UPDATE / MERGE INTO |
|
聚簇优化 | 经常按某列进行过滤,希望提升查询性能 |
|
如需存储和高效查询多模态数据,详情请参见多模态湖。
基本概念
创建 Paimon 表时未指定主键(primary key),该表即为 Paimon Append 表。以下 SQL 创建一张分区键为 dt 的 Append 表:
CREATE TABLE T (
user_id BIGINT,
event_time TIMESTAMP(3),
event_type STRING,
properties STRING,
dt STRING
) PARTITIONED BY (dt);Append 表具有如下特点:
仅追加写入:接收 insert-only 数据流。若上游为 changelog,需确保无 -U/-D 数据,或设置
ignore-delete = true(默认 false)忽略 -U/-D 数据。完善的批读批写能力:类似 Hive 分区表,但额外具备 Time travel(版本回滚)、快速 scan planning(基于分区与列统计 + File Index 裁剪)、Schema evolution(加列、删列、改列、改名无副作用)、行级别删除更新(通过删除向量)。
支持流读流写:可像队列一样灵活地流式读写,延迟在分钟级。
与主键表相比,Append 表适合不需要按主键更新的追加型数据,典型如日志、埋点、ODS 明细、binlog 落地、特征/样本表等。
分桶方式
Append 表支持两种分桶模式。
无分桶(默认)
创建 Append 表时不指定 bucket,或指定 'bucket' = '-1',即为无分桶模式。数据写入时不区分分桶,不保证顺序。该模式优势如下:
写入并行度不受分桶数限制,可使用较高并发写入。
无需预估分桶数,也无需随数据量变化手动调整。
适用于海量追加、不关心顺序与点查的场景,如日志、埋点、ODS 明细等。
固定分桶
在表参数中指定 'bucket' = '<num>'(大于 0 的整数),并通过 'bucket-key' 指定分桶键(多个用逗号分隔),即可设定非分区表的分桶数,或分区表单分区的分桶数。
相比无分桶,固定分桶的优势:
同一桶中的数据按写入顺序读出。若需同 key 数据按序读取,可将其设为 bucket-key。
查询条件包含 bucket-key 的等值(
=)或 IN 条件时,可利用 bucket 裁剪加速查询。两张 Append 表
bucket相同且bucket-key用于 Join 等值条件时,Spark 可利用 Bucketed Join 减少资源消耗。
Spark Bucketed Join 示例:
CREATE TABLE t1 (
user_id BIGINT,
event_type STRING
) TBLPROPERTIES (
'bucket' = '16',
'bucket-key' = 'user_id'
);
CREATE TABLE t2 (
user_id BIGINT,
profile STRING
) TBLPROPERTIES (
'bucket' = '16',
'bucket-key' = 'user_id'
);
-- Bucketed Join
SELECT *
FROM t1
JOIN t2
ON t1.user_id = t2.user_id;行级更新删除
Append 表本身仅追加写入。若需通过 Spark 执行 DELETE / UPDATE / MERGE INTO,可设置 'deletion-vectors.enabled' = 'true'。启用后,删除信息记录到删除向量文件中,查询时据此过滤已删行。DLF 后台优化作业会适时合并删除向量和数据,回收存储空间。
聚簇优化(Clustering)
查询经常按某些列过滤时,可启用 Clustering 对数据重排以提升查询性能。DLF 优化作业定期执行聚簇优化,无需手动运行。
示例:
Flink
-- 无分桶 Append 表
CREATE TABLE app_log (
dt STRING,
log_time TIMESTAMP,
user_id BIGINT,
event_type STRING,
url STRING
) PARTITIONED BY (dt) WITH (
'bucket' = '-1',
'clustering.incremental' = 'true',
'clustering.columns' = 'user_id,event_type'
);
-- 分桶 Append 表
CREATE TABLE app_log (
dt STRING,
log_time TIMESTAMP,
user_id BIGINT,
event_type STRING,
url STRING
) PARTITIONED BY (dt) WITH (
'bucket' = '64',
'bucket-key' = 'user_id',
'bucket-append-ordered' = 'false',
'clustering.incremental' = 'true',
'clustering.columns' = 'event_type'
);Spark
-- 无分桶 Append 表
CREATE TABLE app_log (
dt STRING,
log_time TIMESTAMP,
user_id BIGINT,
event_type STRING
) PARTITIONED BY (dt) TBLPROPERTIES (
'bucket' = '-1',
'clustering.incremental' = 'true',
'clustering.columns' = 'user_id,event_type'
);
-- 分桶 Append 表
CREATE TABLE app_log (
dt STRING,
log_time TIMESTAMP,
user_id BIGINT,
event_type STRING
) PARTITIONED BY (dt) TBLPROPERTIES (
'bucket' = '16',
'bucket-key' = 'user_id',
'bucket-append-ordered' = 'false',
'clustering.incremental' = 'true',
'clustering.columns' = 'event_type'
);Clustering 会重新排序文件,而分桶 Append 表原本有序,因此必须设置 'bucket-append-ordered' = 'false' 才能开启。当前分桶 Append 表聚簇还要求不能开启 Deletion Vectors。
配置说明
场景 1:经常按某些列过滤,希望提升查询性能
'clustering.incremental' = 'true'
'clustering.columns' = 'event_time,user_id'场景 2:分区停止写入后,自动进行全量 clustering
-- 分区超过三天无新写入,视为历史分区
'clustering.history-partition.idle-to-full-sort' = '3d'存储优化资源消耗
Append 表存储优化作业的资源消耗受多种因素影响,难以精确计算。经验值:普通表(200 列以下)每 25 GB 数据约需 1 CU*H。实际以账单为准。
影响因素:
小文件数量:优化作业中打开一个文件的消耗约等于读取 4 MB 数据的消耗。若写入文件普遍较小(10 MB 以下),合并时读取开销更大。可通过减少 bucket 数(分桶表)、降低写入并发(非分桶表)、增大 checkpoint 间隔等方式避免过小文件。
小表共享优化作业:满足条件的多张小表可共享同一优化作业(至多 64 张),节省资源。小表判定条件:
未设置
data-evolution.enabled = true(默认 false)未设置
clustering.incremental = true(默认 false)未设置
deletion-vectors.enabled = true(默认 false)每小时写入数据量小于 16 GB