Iceberg 的 Copy-on-Write 和 Merge-on-Read 怎么选?
面试怎么回答
Copy-on-Write 在更新时重写受影响的数据文件,写放大较大,但读取路径简单,适合读多写少和查询稳定性优先;Merge-on-Read 先写新数据与删除文件,更新更轻,适合 CDC 和高频 Upsert,但查询要合并删除信息,并依赖 Compaction。选型时我会看更新粒度、读写比例、引擎支持、文件布局和维护能力,而不是认为某一种模式永远更快。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
同样是一条 MERGE INTO,有的表写入越来越慢,有的表查询越来越慢。
差别往往不在 SQL,而在更新发生时到底重写数据文件,还是先写删除信息、把合并成本留给读取和后台维护。
Copy-on-Write 把成本放在写入,换取简单读取;Merge-on-Read 让更新更轻,但查询与 Compaction 要承担合并成本。
Copy-on-Write:更新时重写受影响的数据文件
当一批行被更新或删除时,Copy-on-Write 找到相关数据文件,读取未变数据,生成新的数据文件,再通过快照提交替换旧文件。
它的优点是读路径简单:查询主要读取当前数据文件,不需要额外合并大量 Delete File。适合读多写少、更新批次较大、查询延迟要求稳定的场景。
缺点是小范围高频更新也可能重写较大的文件,带来写放大、提交时间和对象存储 I/O。
Merge-on-Read:先记录变更,读取时合并
Merge-on-Read 通常把删除写入 Position Delete 或 Equality Delete 文件,新数据另写 Data File。写入不必立即重写所有旧文件,因此 CDC、高频 Upsert 的延迟和写放大更容易控制。
代价是读取端需要把数据文件和删除文件合并。Delete File 越多,文件打开、过滤和 CPU 开销越高;不同查询引擎对删除文件的优化能力也可能不同。

选择时看四个维度
第一是更新模式。每天一次大批覆盖,更适合把成本集中在写入;持续 CDC 和零散更新,更需要控制单次写放大。
第二是读写比例。报表查询很多且延迟敏感时,读路径越简单越好;写入吞吐更关键、查询可以接受合并成本时,Merge-on-Read 更合适。
第三是文件布局。分区、排序和文件大小决定一次更新会触碰多少文件,也决定删除文件能否高效匹配。模式选择不能脱离表布局。
第四是维护能力。Merge-on-Read 不是“不重写”,而是把重写推迟到 Compaction。必须有数据文件合并、Delete File 清理、快照过期和孤儿文件治理。
一个典型场景
订单明细通过 CDC 每分钟写入。最初使用 Copy-on-Write,每个微批只更新少量订单,却不断重写较大的文件,写入时延逐步上升。
切换 Merge-on-Read 后,写入恢复,但如果长期不做 Compaction,查询扫描的删除文件持续增加,读性能又下降。
真正的方案不是简单切换模式,而是让更新频率、目标文件大小、排序、Compaction 周期和查询 SLA 配套。