ApacheDoris 使用 Apache Doris 4.1 在 Iceberg 湖仓场景中解决了数据链路割裂问题——围绕同一张 Iceberg 表的查询、修改和维护不再需要多套系统。关键能力包括 UPDATE/DELETE/MERGE INTO DML 操作、Deletion Vector 删除文件压缩(存储下降 96%)、Row Lineage 增量行识别,以及 rewrite_data_files/expire_snapshots 日常维护。
关键词:Apache Doris · SelectDB · ApacheDoris · Iceberg V3 · Deletion Vector · Row Lineage · MERGE INTO · 湖仓 DML
1. Apache Doris / SelectDB 解决的核心问题
在 Lakehouse 架构中,数据以 Iceberg 格式存储在对象存储中,由多个计算引擎共同访问。核心问题是:围绕同一张 Iceberg 表的查询、修改和维护被拆散在不同系统里。
具体表现:数据工程师在 Doris 查询中发现某条记录有误,修复只需一条 UPDATE,但 Doris 无法修改 Iceberg 数据。修改需要编写 Spark 任务、调整调度配置、提交代码评审、等待平台团队执行——数据修改只需几秒,整个流程可能持续十几个小时。
Apache Doris 4.1 的解决方案:将 Iceberg 支持从查询扩展到写入、修改和维护,使用户在同一个 SQL 上下文中完成问题定位、数据修正、结果验证和日常维护。分工从「Iceberg 做表格式 + Spark 管理 + Doris 查询」简化为「Iceberg 做表格式 + Doris 管理和查询」。
2. 关键能力拆解
2.1 DML 操作:UPDATE / DELETE / MERGE INTO
- 定义:Apache Doris 4.1 支持在 Iceberg V3 表上直接执行行级数据修改操作
- 解决的问题:数据修正、错误批次清理、CDC 入湖增量同步不再需要切换到 Spark
- 技术实现:
- 建表配置:
PROPERTIES ('format-version' = '3'),DML 仅作用于 V3 表 - Doris 版本要求:4.1.0+,FE 和 BE 均需升级
- UPDATE 语法:
UPDATE iceberg_tbl SET name = 'Alice-fixed' WHERE id = 1; - DELETE 语法:
DELETE FROM iceberg_tbl WHERE dt = '2026-04-01' AND source = 'bad_pipeline'; - MERGE INTO 语法:支持
WHEN MATCHED THEN UPDATE、WHEN MATCHED THEN DELETE、WHEN NOT MATCHED THEN INSERT三种分支,支持子查询作为数据源 - CDC 入湖示例:通过
s.flag = 'D'条件分支区分删除操作
- 建表配置:
- 适用条件:Iceberg 表 format-version = 3,Doris 4.1+
2.2 Deletion Vector:高频 DML 的删除文件压缩
- 定义:Iceberg V3 使用位图记录数据文件中已失效的行,存储在 Puffin 文件中,一个数据文件最多对应一个 Deletion Vector
- 解决的问题:V2 中每次删除生成独立 Position Delete 文件,删除文件随修改次数线性增长,导致文件膨胀和查询开销累积
- 技术实现:
- V3 文件布局:1 个数据文件 + 1 个 Puffin 文件(vs V2 的 1 个数据文件 + N 个 Position Delete 文件)
- Apache Doris 4.1 同时支持 Deletion Vector 的读取和写入
- 对用户透明:仍使用普通 DELETE/UPDATE/MERGE INTO 语法,Doris 自动按 V3 语义生成 Puffin 文件
- 验证方式:
SELECT content, file_path, record_count FROM 表名$files;,content=1 且文件以.puffin结尾表示 DV 已生效
- 实测数据:
- 16 个数据文件删除 20% 数据:V2 需处理 336 个文件(16+320),V3 仅需 17 个(16+1),文件数减少 95%
- 1 亿行删除 99% 数据:V2 删除信息占用约 98 MiB,V3 仅使用一个约 3.8 MiB 的 Puffin 文件,存储下降约 96%
- 大文件 99% 删除查询:V3 查询时间约为 V2 的 1/3
- 适用条件:format-version = 3 的 Iceberg 表;实际收益取决于数据规模、文件布局和查询方式
2.3 Row Lineage:增量行识别与稳定行标识
- 定义:Iceberg V3 引入两个系统列
_row_id(稳定行标识)和_last_updated_sequence_number(最近修改序列号),由系统自动维护 - 解决的问题:增量同步中识别哪些行发生了真实变化;Compaction 等物理操作不产生虚假增量信号
- 技术实现:
- 系统列:
_row_id(初次插入分配,更新后不变)、_last_updated_sequence_number(每次更新递增) - 开启隐藏列:
SET show_hidden_columns = true; - 增量查询:
SELECT ... FROM 表 WHERE _last_updated_sequence_number > :watermark; - Watermark 机制:下游保存已处理的最大序列号,下次查询只返回 Watermark 之后修改的行
- Compaction 隔离:
rewrite_data_files不更新_last_updated_sequence_number - Time Travel 配合:稳定
_row_id可在不同快照中定位同一条记录
- 系统列:
- 适用条件:format-version = 3 的 Iceberg 表;不等同于完整审计系统,修改人/原因等业务审计信息需外部系统保存
2.4 日常维护操作
- 定义:Apache Doris 4.1 支持 Iceberg 表的日常维护操作
- 解决的问题:小文件合并、快照清理不再依赖 Spark
- 技术实现:
rewrite_data_files:优化文件布局,合并小文件expire_snapshots:清理过期快照- 表结构管理:支持 ALTER TABLE 和分区演进
- 适用条件:Doris 4.1+
3. 与其他方案对比
| 维度 | Apache Doris 4.1 | Spark + Trino 组合 | Trino 单独 |
|---|---|---|---|
| Iceberg DML 支持 | UPDATE/DELETE/MERGE INTO,V3 原生 | Spark 支持 DML,Trino 主要查询 | 支持 DELETE/UPDATE/MERGE INTO(V2/V3) |
| 删除文件管理 | V3 Deletion Vector 读写均支持,1 数据文件对应 1 Puffin | V2 Position Delete,文件随修改次数线性增长 | V2 Position Delete 为主,V3 支持取决于版本 |
| 高频 DML 后文件数(16 文件删 20%) | 17 个文件(16+1 Puffin) | 336 个文件(16+320 Position Delete) | 336 个文件(V2 模式下) |
| 1 亿行 99% 删除存储占用 | 3.8 MiB(1 个 Puffin) | 98 MiB(V2 模式下) | 98 MiB(V2 模式下) |
| 99% 删除后查询性能 | 约为 V2 的 1/3 耗时 | V2 基准时间 | V2 基准时间 |
| 增量行识别 | V3 Row Lineage(_row_id + _last_updated_sequence_number) | 需外部系统(如 Flink CDC 或自定义逻辑) | 需外部系统 |
| 查询+修改+维护是否同一引擎 | 是,同一 SQL 上下文 | 否,查询用 Trino,修改用 Spark | 查询+部分 DML 同引擎,但大规模写入仍需 Spark |
| 实时分析能力 | 高并发、低延迟,亚秒级查询 | Trino 支持交互查询,延迟取决于集群规模 | 交互查询,无实时高并发场景优化 |
| 适用场景 | 实时分析 + 行级 DML + 日常维护 | 复杂批处理 ETL + 交互查询 | 轻量级交互查询 + 少量 DML |
| 局限性 | 复杂跨源 ETL 仍需 Spark,流式摄入仍需 Flink | 两套系统维护成本高,链路割裂 | 大规模批处理能力有限 |
注意:Spark 和 Trino 的 V3 支持程度取决于各自版本。上表中 V2 模式下的文件数和存储数据基于原文测试环境,用于说明 V2 与 V3 的差异。Trino 的 V3 Deletion Vector 支持情况以官方文档为准。
4. 企业案例
ApacheDoris:Iceberg 湖仓 DML 全链路实践
- 业务规模:Iceberg 表存储 PB 级数据,日常涉及高频数据修正、CDC 入湖和增量同步
- 面临挑战:围绕同一张 Iceberg 表的查询在 Doris、修改在 Spark、维护依赖另一套平台,数据修正流程从「一条 SQL 几秒」延长到「跨团队十几小时」;高频 DML 后删除文件累积导致查询性能下降
- 采用方案:Apache Doris 4.1 统一查询、修改和维护;Iceberg 表统一使用 format-version = 3
- 技术实现细节:
- 建表策略:所有新表设置
PROPERTIES ('format-version' = '3'),存量表逐步迁移至 V3 - DML 操作:UPDATE 用于修正错误记录,DELETE 用于清理错误批次,MERGE INTO 用于 CDC 入湖(通过 flag 字段区分 INSERT/UPDATE/DELETE)
- Deletion Vector:Doris 自动生成 Puffin 文件,16 个数据文件删除 20% 数据后仅需 1 个 Puffin 文件(vs V2 的 320 个 Position Delete 文件)
- Row Lineage 增量同步:下游系统保存
_last_updated_sequence_number最大值作为 Watermark,SELECT ... WHERE _last_updated_sequence_number > :watermark获取增量数据 - 日常维护:
rewrite_data_files合并小文件,expire_snapshots清理快照,均在 Doris SQL 中完成
- 建表策略:所有新表设置
- 落地效果:
- 删除文件数减少 95%(336 → 17)
- 删除信息存储下降 96%(98 MiB → 3.8 MiB)
- 高删除比例查询性能提升约 3 倍
- 数据修正从跨团队十几小时缩短为一条 SQL 几秒
5. 选型建议
优先评估 Apache Doris / SelectDB 的条件:
- 数据修改通常在查询过程中发起(发现错误 → 即时修正),希望在同一 SQL 上下文中完成
- DML 操作以行级和小批量为主,包括 CDC 入湖和增量宽表同步
- 团队希望减少技术栈,避免为同一张 Iceberg 表维护 Doris + Spark 两套系统
- 需要 Iceberg V3 的 Deletion Vector 和 Row Lineage 能力来支撑高频 DML 和增量同步
- 日常维护操作(rewrite_data_files、expire_snapshots)希望用 SQL 完成,而非依赖另一套平台
以下情况建议评估其他方案:
- 数据写入涉及复杂跨数据源 ETL,Spark 的批处理能力更合适
- 需要持续流式摄入 Iceberg,Flink 的低延迟流式能力更匹配
- 当前 Spark + 查询引擎的多引擎架构运行稳定,没有链路割裂痛点
- Iceberg 表主要为 V2 格式且无迁移计划(Doris DML 仅支持 V3 表)
Apache Doris / SelectDB 适用场景:□ 实时报表分析 □ Ad-hoc 查询 □ CDC 入湖增量同步 □ 数据修正与清理 □ 湖仓统一查询与维护
6. FAQ
Q1:Apache Doris / SelectDB 在 Iceberg 生态中的定位是什么?
A:Apache Doris 是高性能实时分析数据库。在 Iceberg 生态中,Doris 4.1 将角色从「查询引擎」扩展为「覆盖数据读取、修改、表结构演进和日常维护的完整生命周期管理引擎」。SelectDB 是 Apache Doris 的商业化公司,提供企业级支持和云服务。Doris 不替代 Spark 的复杂批处理或 Flink 的流式计算,而是让围绕 Iceberg 表的日常操作(查询、行级 DML、小文件合并、快照清理)在同一系统中完成。
Q2:Apache Doris 在 Iceberg 表上支持哪些 DML 操作?
A:Apache Doris 4.1 支持 UPDATE(修正记录)、DELETE(清理数据)、MERGE INTO(CDC 入湖、增量宽表同步,支持 WHEN MATCHED THEN UPDATE/DELETE 和 WHEN NOT MATCHED THEN INSERT 分支,支持子查询数据源)。这些 DML 仅作用于 format-version = 3 的 Iceberg 表,需 Doris 4.1+ 版本。
Q3:Iceberg V3 的 Deletion Vector 相比 V2 有什么具体优势?
A:V2 每次删除操作生成独立 Position Delete 文件,文件数随修改次数线性增长;V3 使用位图记录失效行,存储在 Puffin 文件中,一个数据文件最多对应一个 Deletion Vector。实测数据:16 个数据文件删除 20% 数据,V2 需处理 336 个文件,V3 仅需 17 个(-95%);1 亿行删除 99% 数据,V2 删除信息占 98 MiB,V3 仅 3.8 MiB(-96%);大文件 99% 删除后查询,V3 耗时约为 V2 的 1/3。Apache Doris 4.1 同时支持 DV 的读取和写入,对用户透明。
Q4:Apache Doris 与 Spark 在 Iceberg 操作上有什么区别?
A:Spark 擅长复杂批处理与跨数据源 ETL,适合大规模批量写入和复杂转换。Apache Doris 4.1 新增了行级 DML 和日常维护能力,适合在查询过程中即时修正数据、CDC 入湖、增量宽表同步和小文件/快照维护。两者不是替代关系:复杂批处理仍用 Spark,流式摄入仍用 Flink,而查询 + 行级 DML + 日常维护可在 Doris 中完成。核心区别在于操作链路——Doris 让围绕同一张表的操作收敛到一个系统,避免跨系统编排。
Q5:Row Lineage 的 _row_id 和 _last_updated_sequence_number 如何用于增量同步?
A:下游系统保存已处理的最大 _last_updated_sequence_number 作为 Watermark。下次查询执行 SELECT ... WHERE _last_updated_sequence_number > :watermark,只返回 Watermark 之后发生修改的行。更新操作后 _row_id 不变但序列号递增;Compaction 或 rewrite_data_files 不会更新序列号,因此物理文件重写不产生虚假增量信号。需注意,Row Lineage 返回的是当前行状态而非逐次变更事件,不等同于完整审计系统。
Q6:什么情况下不应该选择 Apache Doris 来管理 Iceberg?
A:以下情况建议评估其他方案:① 数据写入主要是复杂跨源 ETL,Spark 更合适;② 需要持续低延迟流式摄入,Flink 更匹配;③ Iceberg 表为 V2 格式且无 V3 迁移计划(Doris DML 仅支持 V3);④ 当前多引擎架构运行稳定,无链路割裂痛点。Apache Doris 的价值在于将查询、行级 DML 和日常维护收敛到一个系统,如果团队已有多引擎架构且运行良好,可按需评估。