流式数据湖Paimon探秘之旅 (七) 读取流程全解析

第7章:读取流程全解析

读取的三个阶段

Paimon的读取分为三个阶段:

  1. 扫描计划(Scan):确定需要读取哪些文件
  2. 分片生成(Split):将文件分割成可并行处理的任务
  3. 数据读取(Read):从分片读取实际数据

深入每个阶段

7.1 FileStoreScan扫描接口

扫描的目的

从最新的Snapshot开始,找出所有需要读取的数据文件。

java 复制代码
FileStoreScan scan = fileStore.newScan();

// 应用谓词(where条件)
scan.withFilter(predicate);

// 获得读取计划
Plan plan = scan.plan();

// Plan包含:
// - 所有需要读的文件
// - 文件的元数据(min_key, max_key等)
扫描的性能优化

1. 谓词下推(Predicate Pushdown)

sql 复制代码
SELECT * FROM users WHERE age > 30;

不优化:
  读取: 所有users记录
  过滤: 哪些age > 30
  
优化后:
  检查Manifest:
    - file1: age min=20, max=28 → skip
    - file2: age min=25, max=35 → read ✓
    - file3: age min=30, max=40 → read ✓
  结果: 只读3个文件中的2个

2. 分区裁剪(Partition Pruning)

sql 复制代码
SELECT * FROM events WHERE dt='2024-01-15';

执行:
  读分区列表 → [dt=2024-01-01, dt=2024-01-15, dt=2024-01-31]
  过滤 → [dt=2024-01-15]
  只读dt=2024-01-15目录下的文件
  
效果: 扫描文件数减少 95%

7.2 Split生成与分发

什么是Split?

Split是数据文件的可读取单位,用于分布式读取。

ini 复制代码
原始文件:data-1.parquet (1GB)
        ↓
        Split1: offset=0, length=256MB
        Split2: offset=256MB, length=256MB
        Split3: offset=512MB, length=256MB
        Split4: offset=768MB, length=256MB
        ↓
        4个Split可以并行读取
Split的分配策略
perl 复制代码
单个并行度读取:
  Task-0: 读取所有splits顺序读取
  
多个并行度读取:
  Task-0: 读取 split-0, split-4, split-8, ...
  Task-1: 读取 split-1, split-5, split-9, ...
  Task-2: 读取 split-2, split-6, split-10, ...
  Task-3: 读取 split-3, split-7, split-11, ...
  
  (轮询分配splits)

7.3 SplitRead数据读取

读取的工作流程
java 复制代码
SplitRead<T> read = fileStore.newRead();

for (Split split : splits) {
  RecordReader reader = read.createReader(split);
  
  RecordBatch batch;
  while ((batch = reader.readBatch()) != null) {
    // 处理这批记录
    for (Record record : batch) {
      process(record);
    }
  }
  
  reader.close();
}
批量读取的好处
scss 复制代码
逐记录读取(低效):
  for i in 1..1000000 {
    record = file.read()  ← 1000000次I/O调用!
    process(record)
  }

批量读取(高效):
  for batch in batches {
    batch = file.readBatch(4096)  ← 仅245次I/O调用
    for record in batch {
      process(record)
    }
  }
  
性能提升: 4096倍!

7.4 谓词下推与过滤优化

三层过滤
yaml 复制代码
层1:Manifest级别过滤
  min_key <= target_key <= max_key?
  → 快速排除大量文件
  
层2:文件级别统计过滤
  file_stats:
    age: min=25, max=35
  age > 30?
  → 排除不符合的文件
  
层3:记录级别过滤
  (age > 30)? → keep : skip
  → 最终过滤
where子句的处理
sql 复制代码
WHERE user_id = 100 AND age > 30

分解为:
  谓词1: user_id = 100 (主键谓词 → Manifest过滤)
  谓词2: age > 30 (非主键谓词 → 记录级过滤)

执行:
  1. Manifest过滤 → user_id=100的bucket
  2. 读该bucket的文件
  3. 对每条记录检查 age > 30

总结:读取流程的关键优化

1. 多层过滤链

scss 复制代码
Manifest → 分区 → 文件统计 → 记录级
(快速)     (快速)  (中等)    (精准)

2. 批量处理

css 复制代码
减少I/O次数
减少虚拟机调用开销
提升CPU缓存命中率

3. 分布式并行

复制代码
Split分配 → 并行读取 → 吞吐量线性扩展

相关代码

  • FileStoreScan:paimon-core/src/main/java/org/apache/paimon/operation/FileStoreScan.java
  • SplitRead:paimon-core/src/main/java/org/apache/paimon/io/SplitRead.java
  • Split:paimon-api/src/main/java/org/apache/paimon/table/source/Split.java
相关推荐
SelectDB9 小时前
Apache Doris Python UDF:让 SQL 直接调用 Python 生态,支撑 Agent 时代复杂业务逻辑
大数据·数据库·python
ApacheSeaTunnel11 小时前
当多表数据涌入,Apache SeaTunnel 如何巧妙化解主键冲突?
大数据·开源·数据集成·seatunnel·技术分享·数据同步
大大大大晴天3 天前
Hudi Metadata Table 与 Hive Sync (HMS)怎么选?
大数据
手可摘星辰7774 天前
一次线上FlinkCDC异常排查复盘
大数据·flink
大大大大晴天4 天前
Hudi技术内幕:Metadata Table原理与实践
大数据
大大大大晴天5 天前
Hudi技术内幕:深入解析Index索引机制
大数据
阿里云大数据AI技术5 天前
Flink Forward Asia 2026 深圳启幕:Agentic Streaming for AI,开启实时智能新范式
大数据·flink
SelectDB5 天前
阶跃星辰基于 SelectDB 构建 PB 级 Agent 可观测平台
大数据·数据库·aigc
大大大大晴天9 天前
Hudi技术内幕:RecordPayload到RecordMerger
大数据
SelectDB9 天前
秒级弹性、最高降本 70%:SelectDB Serverless 如何重塑云数仓资源效率
大数据·后端·云原生