四大厂商突然集体站队 Iceberg v3,我花一周搞清楚了为什么

18 阅读21分钟

上周二晚上,我在刷 Snowflake 官方博客的时候注意到一篇不太起眼的公告:Snowflake 开始支持 Apache Iceberg v3 公开预览了。

说实话第一反应是"哦,又一个格式支持"。但接着我往下翻——Databricks 一个月前也发了几乎同样力度的公告。Google Cloud 的 BigQuery、AWS 的 EMR、还有 Dremio,全都在同一时间段内密集释放了 Iceberg v3 相关的内容。

这不对劲。

做数据这行的人都知道,让四家互相抢客户的云厂商在同一件事上"合唱",概率大概和你中彩票差不多。上次看到这种场面还是 Kubernetes 刚火那几年。

于是我决定花点时间搞清楚:Iceberg v3 到底是什么东西,值得这些老对手同时站台?

一周之后,我的结论是:这不是一次普通的版本升级。这是数据湖仓从"实验性质"到"生产就绪"的拐点,也是持续五年的开放表格式之争画上句号的时刻。

先聊个八卦:Databricks 为什么买自己的竞争对手?

在讲技术之前,有个背景必须交代,否则后面很多事情你理解不了。

2023 年 6 月,Databricks 做了一件让整个行业目瞪口呆的事——他们花了 超过 10 亿美元收购了一家叫 Tabular 的公司。

Tabular 是什么公司?它是 Netflix 出来的那批工程师创办的,核心资产就是 Apache Iceberg 的商业化服务。而 Databricks 自己有一套叫 Delta Lake 的表格式,和 Iceberg 是直接竞争关系。

这就好比你开了一家火锅店,然后花重金把隔壁川菜馆的厨师团队全挖过来了。你图什么?

我当时也在纳闷,直到看了 Iceberg v3 的规范才恍然大悟。v3 里有一个叫 Deletion Vector(删除向量) 的特性,它的底层实现逻辑和 Delta Lake 已经用了好几年的删除向量机制几乎一模一样。代码层面的相似度高到让人怀疑是不是同一个人写的——事实上,很可能就是同一批人在两个项目之间做的技术迁移。

Databricks 的算盘打得很精:

  1. 买 Tabular = 掌握 Iceberg 的方向盘。 既然挡不住客户往 Iceberg 跑,那就自己成为 Iceberg 生态里最有话语权的玩家。
  2. 通过 UniForm 技术实现双格式兼容。 用户用 Iceberg 也行,用 Delta Lake 也行,数据不用搬,Databricks 都能赚你的钱。
  3. 护城河上移。 当底层格式变成 commodity(商品),竞争差异化就只能往上走——Unity Catalog、Serverless 计算、AI 平台才是真正赚钱的地方。

所以当你看到 Databricks 在 Iceberg v3 发布后比谁都积极的时候别惊讶——他们花的 10 亿美金需要回报。

graph LR
    A["Netflix 孵化<br/>2018"] --> B["Apache 顶级项目<br/>2020"]
    B --> C["Apple/Netflix/Stripe<br/>大规模采用 2022-23"]
    C --> D["⚡ Databricks 10亿美金<br/>收购 Tabular 2023.06"]
    D --> E["v3 规范通过<br/>2025.06"]
    E --> F["🔥 四大厂商集体宣布支持<br/>2026.03-04"]

    style D fill:#f8d7da,stroke:#dc3545,color:#000
    style F fill:#d1ecf1,stroke:#17a2b8,color:#000

真正的重头戏:五个改变游戏规则的特性

好了,八卦聊完,进入正题。Iceberg v3 一共引入了五个主要特性,我按重要程度排序,一个一个说。

特性一:删除向量——治好了一个折磨了我三年的病

先说个真事。

去年我在帮一个电商客户优化他们的数仓,核心问题是订单表的查询越来越慢。这张表大概 10TB,每天有大量的 upsert 操作(用户下单→支付→取消→重新下单,每一步都会产生行级更新)。

排查下来发现,这张表积累了 两万三千多个 positional delete 文件。什么概念?就是每次查询的时候,引擎要先读取这两万多个小文件来确定哪些行该跳过,然后再去读真正的数据文件。一次简单的 SELECT count(*) 要跑四十多分钟。

最后怎么解决的?停掉所有写入窗口,专门跑了六个小时的全量 Compaction 把删除记录合并回去。客户的数据管道中断了大半夜,业务方差点拿着刀来找我们。

这就是 Iceberg v2 在高频更新场景下的真实面貌:能用,但用得很痛苦。

v2 到底哪里出了问题

Iceberg v2 支持 Merge-on-Read 模式下的行级删除,原理很简单——删一行数据时,不修改原始 Parquet 文件,而是额外生成一个小文件记录 "文件 X 的第 Y 行被删了"。查询时引擎把这些删除文件合并进来做过滤。

这个设计在纸面上很优雅(不可变文件 + 追加式删除标记),但在生产环境中会遭遇三个致命问题:

问题一:文件数量失控。

每次批量删除操作都会产生新的 delete 文件。如果你的 CDC 任务每小时跑一次、每天跑 10 张表、每张表 10 个分区,一天就能产生几百个小文件。这些文件单个只有几 KB 到几十 KB,但对 HDFS / S3 的 NameNode 来说每个文件都是一次元数据调用。积累几个月之后,光是列出所有文件名就可能要几分钟。

问题二:读放大效应。

前面说的那个两万文件案例不是夸张。当删除文件数量远超数据文件数量时,查询引擎的大部分时间花在了"合并删除标记"这件事上,而不是真正的查询计算。而且这个问题没有自我修复机制——你不手动触发 Compaction,它只会越来越慢。

问题三:Compaction 是把双刃剑。

Compaction 本身就是一个重量级操作。它需要读取数据文件 + 读取所有关联的删除文件 → 合并 → 重写新的干净数据文件 → 清理旧文件。整个过程消耗大量 CPU 和 IO,期间还可能影响正在运行的查询。所以很多团队的策略是"周末凌晨跑 Compaction"——但这意味着你的表在一周内性能是持续衰减的。

v3 怎么解决这些问题

删除向量(Deletion Vector) 的思路是换一种方式来存储"哪些行被删了"这个信息。

不再为每次删除操作生成独立文件,而是为每个数据文件维护最多一个删除向量。底层使用 Roaring Bitmap 数据结构——一种针对稀疏位图做了极致优化的压缩算法。

Roaring Bitmap 的巧妙之处在于它根据数据的分布情况自动选择编码方式:

  • 如果被删除的行位置比较集中(比如连续删了一整段数据),就用简单位图,每个 bit 代表一行,压缩率极高
  • 如果被删除的行位置很分散(随机删除零星几行),就切换成数组模式,只存具体的行号

实测效果:同样的删除量级,删除向量的存储体积只有 positional delete 文件的 1/10 到 1/20

graph TD
    subgraph "❌ v2 的困境"
        direction TB
        P1[数据文件 orders_001.parquet] --> D1[delete_001.del]
        P1 --> D2[delete_002.del]
        P1 --> D3[delete_003.del]
        P1 --> D4[delete_004.del]
        P1 --> D5["... (N 个文件)"]
        
        D1 & D2 & D3 & D4 & D5 --> Q1["查询时: 加载 N 个文件<br/>内存合并 → 过滤<br/>IO 开销巨大"]
        
        style Q1 fill:#f8d7da,stroke:#dc3545,color:#000
        style D1 fill:#fce4ec,stroke:#e91e63,color:#000
        style D2 fill:#fce4ec,stroke:#e91e63,color:#000
        style D3 fill:#fce4ec,stroke:#e91e63,color:#000
    end
    
    subgraph "✅ v3 的方案"
        direction TB
        P2[数据文件 orders_001.parquet] --> DV["📦 单个删除向量<br/>Deletion Vector<br/>Roaring Bitmap<br/>Puffin 格式"]
        
        DV --> Q2["查询时: 读取 1 个文件<br/>位运算跳过已删除行<br/>IO 接近于零"]
        
        style DV fill:#d4edda,stroke:#28a745,color:#000
        style Q2 fill:#d4edda,stroke:#28a745,color:#000
    end

Databricks 公开的基准测试数据显示:相比 Copy-on-Write(每次更新都重写整个文件的"笨"办法),删除向量快大约 10 倍;相比 v2 的 positional delete,快 3 到 5 倍。更关键的是,查询侧的性能基本不受影响——因为只需要加载一个紧凑的二进制文件做位运算过滤。

还有一个细节我觉得特别值得玩味:删除向量的设计和 Delta Lake 用了多年的 Deletion Vector 在二进制编码层面是完全一致的。 这不是巧合。Databricks 收购 Tabular 之后,把自己在 Delta Lake 上踩过的坑、优化过的方案直接带到了 Iceberg 社区。从某种意义上说,v3 是开放源代码和商业产品技术融合的第一个实质性成果。

特性二:行级血缘——CDC 终于不用折腾了

如果你做过实时数仓或者任何需要增量处理数据的系统,你应该对下面这个场景不陌生:

上游的业务数据库每秒钟都在产生变更(INSERT、UPDATE、DELETE)。你需要把这些变更实时同步到数据仓库里,然后让下游的报表/ML 模型/BI 工具基于最新的数据做计算。

听起来简单?那你可能没踩过下面的坑。

我试过的 CDC 方案,每一个都有毛病

方案一:时间戳字段法

给每张表加一个 updated_at 字段,定时任务扫描 WHERE updated_at > 上次处理时间

问题在哪?同一秒内如果有多条更新,你只能靠额外的排序字段来保证顺序,而且精度天然受限。更大的问题是全表扫描——即使一秒钟只有 10 行变了,你也要扫描整个分区来找到它们。表大了以后这个开销不可接受。

方案二:Debezium + Kafka

目前业界最主流的做法。Debezium 监听数据库 binlog,把变更事件发到 Kafka,下游消费端处理。

功能强大是真的强大。但它引入了一套全新的基础设施要维护:ZooKeeper、Kafka 集群、Schema Registry、Connect 集群……任何一个环节出了问题,整条数据链路就断了。而且当上游表结构变更时(加列、改类型),Debezium 的 schema evolution 处理并不总是平滑的——我见过因为上游改了一个字段类型导致 Kafka 消息积压了几百万条的惨案。

方案三:数据库原生 binlog 解析

MySQL binlog、PostgreSQL WAL、Oracle GoldenGate……

强依赖特定数据库。你今天用的是 MySQL,明天业务说要迁 PostgreSQL,整套 CDC 方案推倒重来。而且在云原生环境下(RDS、Aurora),你对 binlog 的控制权是有限的。

上面三种方案有一个共同点:它们都是在表的外面套一层追踪机制。 表本身不知道自己被改过什么,需要外部工具来告诉你。

v3 的思路:让表自己记住

Iceberg v3 引入了原生的 Row Lineage(行级血缘)。核心设计是在规范层面强制要求每一行数据携带两个元数据字段:

元数据字段它是什么为什么重要
_row_id全局唯一的行标识符类似主键,但由 Iceberg 分配,跨文件移动也不变
_last_updated_sequence_number该行最后一次变更时的提交序号可以精确知道"这行数据是什么时候变的"

这两个字段不是你需要自己维护的东西——引擎自动管理。 你 INSERT 一行数据,_row_id 自动分配;你 UPDATE 了某一行,它的 _row_id 不变但 _sequence_number 更新为新提交的序号。

flowchart TD
    WRITE["写入端: INSERT / UPDATE / DELETE"] --> |"引擎自动附加"| META["_row_id (不变) + _sequence_number (递增)"]
    
    META --> SNAP["快照: 每次提交生成新版本元数据"]
    
    SNAP --> CONSUME["消费端: SELECT * FROM table<br/>WHERE _sequence_number > 上次处理的序号"]
    
    CONSUME --> RESULT["✅ 只返回真正变化的行<br/>✅ 无需外部 CDC 工具<br/>✅ 无需全表扫描"]

    style RESULT fill:#d4edda,stroke:#28a745,color:#000
    style CONSUME fill:#fff3cd,stroke:#ffc107,color:#000

这意味着什么?意味着你的物化视图刷新可以这样做:

-- 只处理上次刷新以来变化过的行
-- 不需要全表重算,不需要 Debezium,不需要 Kafka
REFRESH MATERIALIZED VIEW mv_order_daily
AS SELECT * FROM orders 
WHERE _last_updated_sequence_number > (SELECT last_refresh_seq FROM mv_metadata);

对于 GDPR 合规场景,审计部门问"这条用户数据是谁在什么时候修改的",你不需要翻 ELK 日志、不需要查应用层 audit log——直接查 Iceberg 的行级血缘就行。

对于 AI/ML 数据管道,训练数据的变更可追溯性变得原生可用。模型训练出问题了?回溯一下最近有哪些行的 sequence number 发生了异常变化,大概率能定位到数据质量问题的根源。

有一点必须诚实地说: 行级血缘只对升级到 v3 之后的新增变更生效,不会回填历史数据。升级前已经存在的那些行不会有 _row_id。这是一个合理的设计取舍——回填 PB 级数据的历史 lineage 成本太高了,不如让新旧数据自然过渡。

特性三:VARIANT 类型——半结构化数据的终极答案?

这个问题我想吐槽很久了。

做数据工程的人应该都有这种经历:上游系统(App 后端、IoT 设备、第三方 API)丢过来一堆 JSON 数据,里面的字段今天长这样明天长那样,schema 变得比我的心跳还频繁。

你怎么存进数据仓库?三条路,每条都不好走。

三条烂路

路一:展平成宽表

把 JSON 里所有可能的字段拆成独立的物理列。

结果就是一张拥有 300+ 列 的怪物表格,其中 80% 是 NULL。每当上游加一个新字段,你就得 ALTER TABLE ADD COLUMN,然后等元数据在整个链路上同步。三个月之后你的表结构变成了没人敢动的祖传代码——改一行可能影响十个下游任务。

路二:当字符串塞进去

最省事的办法:整个 JSON 作为一个 STRING 或 VARCHAR 列存起来。

查的时候呢?payload LIKE '%event_type=purchase%' —— 全表扫描,逐行字符串匹配,一张千万级的表跑个过滤条件要半小时。或者写个 UDF 用 JSON 解析库逐行解析,好一点但还是慢,而且 UDF 的性能在不同引擎间差异巨大。

路三:ETL 流水线预处理

最"正规"的做法:入库前用 Spark/Flink 做一套 ETL 把 JSON 结构固定下来。

问题是上游的 schema 变更永远比你 ETL 脚本的迭代速度快。你上周刚处理好的字段,这周上游把它从 user_id 改成了 userId,下周又嵌套了一层 metadata 对象。你的 ETL 脚本最终会变成一堆 when ... otherwise ... case when ... 的意大利面条。

v3 给出的答案

Iceberg v3 引入了原生的 VARIANT 数据类型。名字借用了 Snowflake 的同名类型——这不是巧合,后面会说。

VARIANT 的本质是一种 自描述的二进制编码格式。你可以把任意结构的半结构化数据(JSON、嵌套对象、数组、混合类型)直接存进去,同时在底层保持接近结构化数据的查询效率。

它在 Parquet 文件中的物理存储结构是这样的:

┌─────────────────────────────────────┐
│         Variant Column               │
├──────────────────┬──────────────────┤
│   metadata       │   value          │
│   (binary)       │   (binary)       │
│                  │                  │
│ • 键名字典       │ • value_metadata │
│   (去重+排序)    │   (类型描述)     │
│ • 各字段偏移量   │ • value_data     │
│                  │   (实际编码值)   │
└──────────────────┴──────────────────┘

metadata 部分存的是"结构信息"——有哪些键、它们在哪里、什么类型。value 部分存的是实际的数值。两部分分开存储的好处是:很多时候你只需要读 metadata 就能回答查询优化器的问题(比如"这个文件里有没有 action='purchase' 的记录?"),根本不用解压 value 部分。

但 VARIANT 最聪明的设计在于 Shredding(分片) 技术。

当引擎检测到 VARIANT 列中的某些字段被频繁访问时(比如你的 SQL 里经常出现 WHERE payload:action = 'purchase'),它会在写入时把这些热门字段提取出来,变成独立的、带类型的 Parquet 物理列。

原始 JSON: {"event_type": "noop", "event_ts": 1729794114937, "user_id": 10086, "action": "purchase"}

分片后:
├── event_type (STRING 列)     ← 独立 Parquet 列, 可谓词下推
├── event_ts (LONG 列)         ← 独立 Parquet 列, 有统计信息
├── user_id (LONG 列)           ← 独立 Parquet 列
├── action (STRING 列)          ← 独立 Parquet 列 ← 这个字段被频繁查询
└── _remaining (BINARY blob)    ← 其余不常用的字段保留在这里

这样你就同时拥有了两个世界的优点:

  • 热门字段的查询性能 ≈ 结构化列(谓词下推、统计信息、文件裁剪全部生效)
  • 冷门字段不会导致宽表爆炸(藏在 blob 里,不影响 Schema)
  • 上游加了个新字段?直接存进去,不用改表结构
-- 建 v3 表,带 VARIANT 列
CREATE TABLE events (
    event_id BIGINT,
    ts TIMESTAMP_NS,
    payload VARIANT            -- 半结构化数据,想塞啥塞啥
) USING iceberg 
TBLPROPERTIES ('format-version' = '3');

-- 写入,不用预先定义 payload 内部结构
INSERT INTO events VALUES 
(1, TIMESTAMP '2026-04-13T10:00:00', parse_json('{"user_id": 10086, "action": "purchase", "amount": 299.00}'));

-- 查询,语法直观,谓词下推生效
SELECT payload:user_id, payload:action, payload:amount
FROM events 
WHERE payload:action = 'purchase'      -- 这个条件下推到存储层
  AND ts >= TIMESTAMP '2026-04-01';

这里要特别提一句 Snowflake 的贡献。Snowflake 的 VARIANT 类型在生产环境已经跑了七八年,处理半结构化数据的经验可以说是业界最丰富的。Iceberg v3 的 VARIANT 设计大量借鉴了 Snowflake 的实战经验——包括二进制编码方式、分片策略、查询优化路径。事实上 Snowflake 四天前刚发了一篇非常硬核的工程博客详细解释了他们的 VARIANT 实现,感兴趣的话可以去看看(链接在文末参考资料)。

特性四和特性五:两个补齐最后拼图的改动

这两个相对"小",但在特定场景下不可或缺。

默认列值(Default Column Values):

你有没有经历过给一张 PB 级的大表加一列的操作?

传统流程:

  1. ALTER TABLE ADD COLUMN new_col STRING DEFAULT 'normal'
  2. 引擎开始回填所有已有的数据文件,给每行加上 'normal'
  3. 等待……等待……等待……(取决于表大小,几小时到几十小时不等)
  4. 回填期间表处于不一致状态:有些文件有新列,有些没有

v3 的做法极其简洁:只在元数据层面声明默认值,不动任何数据文件。 查询时如果某行缺少这一列,引擎自动用声明的默认值填充。不管表多大,这个操作都是亚秒级的。

-- 10 亿行的表?瞬间完成。
ALTER TABLE orders ADD COLUMN priority STRING DEFAULT 'normal';

-- 新插入的行可以覆盖默认值
INSERT INTO orders (...) VALUES (... , 'urgent');

纳秒级时间戳(Nanosecond Timestamps):

v3 新增 timestamp_nstimestamptz_ns 两种类型。微秒精度(μs,10⁻⁶ 秒)对大多数场景够了,但这些不够:

  • 高频交易系统:两笔交易之间的时间差可能是纳秒级别,排序判定需要更高精度
  • IoT 传感器网络:5G/6G 环境下设备上报频率达到微秒级,纳秒精度才能保证事件顺序
  • 分布式系统调试:多节点时钟同步误差分析需要比微秒更高的分辨率

以前遇到这种需求只能在应用层用 LONG 型存 Unix 纳秒时间戳,丢失了时区语义和内置的时间函数支持。现在终于有原生的了。

各家云厂商的态度,比技术更有意思

技术聊完了,来看看各家的站位。这部分其实比新特性更能说明问题。

Databricks:最激进的"叛徒"

我用"叛徒"这个词不带贬义。作为 Delta Lake 的缔造者,Databricks 本应该是 Iceberg 最坚定的反对者。但现实是他们现在是 Iceberg v3 最积极的推动者:

  • 收购 Tabular 后立刻加速 v3 规范的推进
  • UniForm 技术让 Delta ↔ Iceberg 双向兼容,用户无感知切换
  • Public Preview 第一时间上线
  • 官方文档里 Iceberg 和 Delta 平起平坐

背后的战略逻辑我在开头已经分析了。当底层格式不可避免地变成 commodity 时,赚钱的方式就不再是卖格式本身,而是卖围绕格式的完整服务体验。

Snowflake:从观望者到全力投入

Snowflake 的转变轨迹很有代表性。

作为一个封闭架构数据仓库的代表,Snowflake 曾经对开放表格式相当谨慎——毕竟越开放,客户越容易带着数据迁移走。但过去一年他们的态度发生了明显转向:

  • 2026 年 3 月宣布 Iceberg v3 公开预览支持
  • 4 月 9 日(就在几天前)发了 VARIANT 类型的深度工程博客,由核心工程师撰写,细节到了 Parquet 存储结构的 byte 级别
  • 强调"无缝集成",目标是用熟悉的 Snowflake SQL 直接操作 Iceberg 表

Snowflake 的判断很清晰:与其试图阻挡开放标准的浪潮,不如让自己成为这个标准上最好的执行者。 当客户可以在 Snowflake 内以同等效率和体验操作 Iceberg 表时,留下的理由就不是锁定,而是服务和性能。

AWS 和 Google Cloud:顺水推舟

对这两家来说,Iceberg 是卖云资源的杠杆。客户用的表格式越开放、标准化,数据就越自然地落在 S3 或者 GCS 上。EMR、Athena、Glue、BigQuery——全线跟进 v3 支持几乎是必然的选择。

Dremio:纯血统的 Iceberg 信徒

Dremio 从第一天起就基于 Iceberg 构建。对他们来说,每一次 Iceberg 版本升级都直接等于产品能力提升。v3 规范通过的当天他们就发了技术解读博文——这种反应速度只有"自己人"才做得到。

quadrantChart
    title 各厂商 Iceberg v3 投入度
    x-axis "被动跟随" --> "主动推动"
    y-axis "有限支持" --> "深度集成"
    quadrant-1 "领跑者"
    quadrant-2 "跟随者"
    quadrant-3 "观察者"
    quadrant-4 "务实派"
    Databricks: [0.85, 0.90]
    Google_Cloud: [0.75, 0.75]
    AWS: [0.70, 0.70]
    Snowflake: [0.65, 0.80]
    Dremio: [0.90, 0.65]

升不升级?给你一份诚实的决策树

聊了这么多,落到实际问题。以下是我基于调研给出的建议:

✅ 立刻升级的情况:

  • 你的表存在高频 upsert/CDC 操作,删除文件管理已经是运维负担(如果你不知道什么叫"删除文件负担",说明你可能还没遇到——恭喜)
  • 你在处理大量半结构化数据,JSON 展平或字符串存储方案已经撑不住了
  • 你的项目涉及合规审计需求(GDPR、HIPAA、SOX 等),需要细粒度的数据变更追溯
  • 你的查询引擎已经发布了稳定的 v3 支持版本

⏸️ 再等等的情况:

  • 你的表以 append-only 批量写入为主,很少做行级更新——v2 的 Copy-on-Write 对你来说够用了
  • 生产环境的引擎版本还比较旧,Spark < 4.0 / Flink < 2.x 之类——v3 需要引擎端配合,单边升级没意义
  • 团队还在消化 v2 的最佳实践(隐藏分区、快照隔离、时间旅行这些还没玩熟)

❌ 别碰的情况:

  • 你的数据平台还在用 Hive 格式——先把 Iceberg v1/v2 的迁移搞定再说,步子太大容易扯着蛋
  • 对稳定性要求极高且没有充足的测试环境——任何大版本升级都有风险,别拿生产练手

升级操作本身倒是意外地简单:

-- 一条语句,原子操作,不重写数据文件
ALTER TABLE my_table SET TBLPROPERTIES ('format-version' = '3');

但我强烈建议不要上来就对核心表执行这条命令。稳妥的路径是:

  1. 开发环境创建几张 v3 新表,验证所有相关引擎和工具的兼容性
  2. 选一两张低风险的非核心表先行升级,观察一周左右
  3. 确认 Compaction 行为、查询性能、写入延迟都在预期范围内
  4. 逐步推广到更多表,保留最近几个 v2 的快照以备紧急回滚

我做数据工程这行八年了,见证了 Hive 格式的统治期、NoSQL 数据库的泡沫期、Spark 统一批处理的崛起、再到这几年数据湖仓概念的反复炒作。说实话,这个行业里真正让我觉得"这次不一样"的时刻并不多。

Iceberg v3 是其中之一。

不是因为某个单一的技术突破有多惊艳——删除向量、行级血缘、VARIANT 类型,单独拿出来看都不是革命性的创新。Delta Lake 很早就有了类似的删除向量,Snowflake 的 VARIANT 也跑了好几年了。

真正重要的是这些东西出现在了同一个开放标准里,并且得到了全行业的共同背书。

过去五年,"到底用什么表格式"这个问题消耗了太多人的精力。技术选型会上吵得面红耳赤,POC 跑了一圈又一圈,最后选了哪个都不完全满意。这种争论推动了进步没错,但当争论持续太久,就开始变成内耗了。

v3 是一个明确的信号:选型焦虑该结束了。 不管你用的是哪家云、哪个计算引擎、哪种 BI 工具,Iceberg v3 都能提供一个可靠的、开放的、高性能的基础数据层。

这不代表 Iceberg 是完美的。它不会帮你自动调优查询、不会替你设计数据模型、也不会让你的数据治理问题凭空消失。但它至少让你可以把精力从"底层格式怎么选"转移到更有价值的问题上——数据质量怎么保障?AI 模型怎么用好这些数据?业务洞察怎么能更快落地?