Paimon 作为实时数据湖框架,得益于Paimon的LSM-Tree结构设计,有非常不错的查询性能。本文主要介绍Paimon的查询优化常见的概念和手段。
在Paimon中进行读取优化时,可以从多个维度入手,包括表结构设计、存储参数配置、查询计划优化以及集群资源调优等。以下是一些关键的优化方向和具体措施:
表结构与存储优化
表模式选择
Paimon表类型分为主键表和非主键表表。
非主键表类似于传统的 Hive 表,没有主键设置。值得注意的是,Paimon 的 Append 表在 checkpoint 提交数据。这种强一致性保证,不会因为 Paimon 任务 checkpoint 失败而导致数据丢失或者重复,可以达到 Exactly-Once。
主键表的文件结构大致如下所示,表或分区包含多个桶(bucket),每个桶是一个独立的 LSM 树结构,包含多个文件。LSM 的写入过程大致如下:Flink checkpoint 会刷新 L0 文件,并根据需要触发 compaction 以合并数据。根据写入时的处理方式不同,有以下三种模式:
-
MOR (Merge On Read):默认模式,仅执行 minor compaction,读取时需要合并。
MOR(默认):适合读写混合场景,写入性能非常好,需要定期合并文件。
-
COW (Copy On Write):使用'full-compaction.delta-commits' = '1',同步进行 full compaction,即在写入时完成合并。
适合写少读多场景,查询时无需合并数据。
-
MOW (Merge On Write):使用'deletion-vectors.enabled' = 'true',在写入阶段,LSM 会查询并生成数据文件的 deletion vector 文件,在读取时直接过滤掉不必要的行。
适合写多读少场景,写入时实时合并。
表结构设计
合理设计分区与分桶
-
分区键:选择查询高频过滤的字段(如时间、地域)作为分区键,减少扫描范围。
CREATE TABLE optimized_table (
dt STRING,
region STRING,
id INT PRIMARY KEY,
name STRING
) PARTITIONED BY (dt, region) -- 按日期和区域分区
WITH (
'bucket' = '8' -- 根据数据量和查询并发度调整分桶数
);
-
分桶策略:对 JOIN 高频的字段分桶,提升 JOIN 性能。
配置文件格式与压缩
WITH (
'file.format' = 'parquet', -- Parquet比ORC更适合Paimon
'parquet.compression' = 'zstd' -- 压缩算法:snappy/lz4/zstd
);
查询参数优化
主键和谓词下推
对于常规的分桶表(例如,bucket = 5),主键的过滤条件将大大加速查询并减少大量文件的读取。所以可以如果是经常性通过主键进行点查,所以合理设计主键字段是非常有效的选择。
确保SQL查询中尽早过滤数据,减少数据扫描量:
SELECT id, name
FROM table
WHERE dt = '2023-10-01' AND age > 18; -- 过滤条件前置
读取并行度调整
SET 'table.exec.source.parallelism' = '16'; -- 根据集群资源和数据量调整
批量读取参数
WITH (
'scan.batch-size' = '1000', -- 批量读取行数
'scan.partition-batch-size' = '10' -- 每个分区的批量处理数
);
合理设计索引
Paimon 提供了多种索引机制,包括布隆过滤器(Bloom Filter)、分区索引和聚簇索引等。
-
布隆过滤器索引
Paimon 支持 Bloom Filter,可以快速判断某个文件中是否包含某个字段值,显著提高对应列值在 Data File 中的 SCAN 效率,适用于等值查询(如WHERE id = 123),不适合范围查询(如WHERE age > 18),对高频过滤的字段(如主键、外键)效果显著。
CREATE TABLE user (
id INT PRIMARY KEY,
name STRING,
age INT
) WITH (
'bloom-filter.columns' = 'id,name', -- 对id和name字段添加布隆过滤器
'bloom-filter.fpp' = '0.01' -- 误判率,默认0.01(值越小,过滤器越大)
);
-
分区索引
对按时间、地域等维度分区的表,分区键自动成为索引。适合查询条件中包含分区键的场景(如WHERE dt = '2023-10-01')。
在创建表时定义分区键:
CREATE TABLE order_detail (
dt STRING, -- 日期分区键
order_id STRING,
amount DOUBLE
) PARTITIONED BY (dt) -- 按日期分区
WITH (
'bucket' = '4' -- 分桶数
);
-
聚簇索引
对经常一起查询的字段进行聚簇存储,提升多字段查询性能。例如,查询常同时过滤category和price字段。
在创建表时指定聚簇字段:
CREATE TABLE product (
category STRING,
price DOUBLE,
name STRING
) WITH (
'clustering' = 'category,price' -- 按category和price聚簇
);
当查询同时过滤这两个字段时,数据物理上更接近,减少 IO:
SELECT * FROM product WHERE category = 'electronics' AND price < 1000;
此外,我们还可以通过监控读取算子的吞吐量和延迟,查看Paimon的Metrics(如扫描文件数、过滤率)。
最后,欢迎加入我们的知识星球小圈子:
《300万字!全网最全大数据学习面试社区等你来》。

