引言
2026年5月29日,DuckDB 团队发布了 Iceberg 扩展的重大更新博客,带来了多项备受期待的功能。作为 DuckDB v1.5.3 的一部分,这些新特性大幅缩小了 DuckDB-Iceberg 与传统 Iceberg 引擎之间的功能差距,涵盖了写入操作、模式演化、高级分区策略以及最新的 Iceberg V3 格式支持。
在此之前,DuckDB 对 Iceberg 的支持主要集中在读取和数据写入的基础能力上。随着 v1.5.3 的发布,MERGE INTO、ALTER TABLE、bucket/truncate 分区变换和 V3 格式等关键功能已全面可用。本文将逐一深入解析这些新特性,并通过可执行的 SQL 示例帮助读者快速上手。
对于正在构建数据湖仓(Lakehouse)架构的团队来说,这些更新意味着 DuckDB 可以更加无缝地融入现有的 Iceberg 生态,无论是作为查询引擎还是数据写入工具。
一、MERGE INTO:一键式 Upsert 操作
功能概述
MERGE INTO(也称为 Upsert)是数据湖场景中最常用的写入模式之一。当目标表没有主键约束时——这正是所有湖仓格式的共同特性——MERGE INTO 成为表达"插入或更新"语义的标准方式。
在 v1.5.3 之前,DuckDB-Iceberg 用户需要通过先查询、再判断、然后分别执行 INSERT 或 UPDATE 的方式来实现类似功能,这不仅代码冗长,而且无法保证原子性。现在,一条 MERGE INTO 语句即可完成全部操作。
代码示例
假设我们有一个人员信息表:
-- 创建 Iceberg 表
ATTACH 'my_warehouse' AS my_datalake (TYPE iceberg);
CREATE TABLE my_datalake.default.people (
id INTEGER,
name VARCHAR,
salary FLOAT
);
-- 插入初始数据
INSERT INTO my_datalake.default.people
VALUES (1, 'John', 92000.0), (2, 'Anna', 100000.0);
-- 查看当前数据
SELECT * FROM my_datalake.default.people ORDER BY id;
输出:
┌───────┬─────────┬──────────┐
│ id │ name │ salary │
│ int32 │ varchar │ float │
├───────┼─────────┼──────────┤
│ 1 │ John │ 92000.0 │
│ 2 │ Anna │ 100000.0 │
└───────┴─────────┴──────────┘
现在,我们想要同时更新 John 的薪资并新增一名员工 Sarah:
MERGE INTO my_datalake.default.people AS target
USING (
FROM (VALUES
(1, 'John', 105000.0),
(3, 'Sarah', 95000.0)
) t(id, name, salary)
) AS upserts
ON (upserts.id = target.id)
WHEN MATCHED THEN UPDATE
WHEN NOT MATCHED THEN INSERT;
查询结果确认操作已生效:
SELECT * FROM my_datalake.default.people ORDER BY id;
┌───────┬─────────┬──────────┐
│ id │ name │ salary │
│ int32 │ varchar │ float │
├───────┼─────────┼──────────┤
│ 1 │ John │ 105000.0 │
│ 2 │ Anna │ 100000.0 │
│ 3 │ Sarah │ 95000.0 │
└───────┴─────────┴──────────┘
高级用法:DELETE 分支
MERGE INTO 还支持 WHEN MATCHED THEN DELETE 分支,可以在同一条语句中同时处理更新和删除操作:
MERGE INTO my_datalake.default.people AS target
USING (VALUES (2, 'Anna', 0.0)) AS changes(id, name, salary)
ON (changes.id = target.id)
WHEN MATCHED AND changes.salary = 0.0 THEN DELETE
WHEN MATCHED THEN UPDATE
WHEN NOT MATCHED THEN INSERT;
DuckDB-Iceberg 的 MERGE INTO 采用 merge-on-read 语义,写入时将删除位置信息记录到 Iceberg 表中,读取时再合并。这种方式避免了重写整个数据文件的开销,特别适合频繁更新的大表。
二、ALTER TABLE:完整的 Schema 演化能力
功能概述
在 v1.4 版本中,DuckDB-Iceberg 的一个主要限制就是不支持模式演化(Schema Evolution)。这意味着一旦表被创建,其结构就无法修改——无法添加列、重命名列或删除列。对于生产环境的数据湖来说,这显然是不可接受的。
v1.5.3 彻底解决了这个问题。现在 ALTER TABLE 支持以下操作:
| 操作 | 说明 | 是否支持 |
|---|---|---|
| RENAME TABLE | 重命名表 | ✅ |
| ADD COLUMN | 添加新列 | ✅ |
| RENAME COLUMN | 重命名列 | ✅ |
| DROP COLUMN | 删除列 | ✅ |
| SET format-version | 设置格式版本 | ✅ |
代码示例
-- 创建测试表
CREATE TABLE my_datalake.default.simple_table AS
FROM (VALUES
(1, 'Andy'),
(2, 'Bob'),
(3, 'Claire'),
(4, 'Mr. Duck')) t(col1, col2);
-- 重命名表
ALTER TABLE my_datalake.default.simple_table
RENAME TO renamed_table;
-- 添加列
ALTER TABLE my_datalake.default.renamed_table
ADD COLUMN col3 DOUBLE;
-- 重命名列
ALTER TABLE my_datalake.default.renamed_table
RENAME COLUMN col2 TO name;
-- 删除列
ALTER TABLE my_datalake.default.renamed_table
DROP COLUMN col3;
-- 设置格式版本为 V3
ALTER TABLE my_datalake.default.renamed_table
SET ('format-version' = 3);
-- 查询结果
SELECT * FROM my_datalake.default.renamed_table ORDER BY col1;
┌───────┬──────────┐
│ col1 │ name │
│ int32 │ varchar │
├───────┼──────────┤
│ 1 │ Andy │
│ 2 │ Bob │
│ 3 │ Claire │
│ 4 │ Mr. Duck │
└───────┴──────────┘
原理说明
ALTER TABLE 在底层更新 Iceberg 表的 current-schema-id,所有变更均通过 Iceberg REST Catalog 写入。由于 Iceberg 模式演化是纯元数据操作,数据文件不会被重写,因此执行速度极快且不影响现有数据。其他 Iceberg 兼容引擎(如 Spark、Trino)在下次查询 LoadTableInformation 端点时会立即看到这些变更。
三、bucket 与 truncate 分区变换
功能概述
Iceberg 规范定义了一系列分区变换(Partition Transforms),用于决定数据文件在磁盘上的布局方式。v1.5.3 新增了对 bucket 和 truncate 两种变换的支持。
bucket(N, col):将列的值哈希到 N 个桶中。适合高基数列的稳定分区,例如用户 ID。truncate(W, col):按列值的前 W 个字符(字符串)或列值向下取整到 W 的倍数(数值)进行分组。适合前缀分区,例如国家代码。
代码示例
CREATE TABLE my_datalake.default.events (
event_id BIGINT,
user_id BIGINT,
country VARCHAR,
payload VARCHAR
)
PARTITIONED BY (bucket(16, user_id), truncate(2, country));
INSERT INTO my_datalake.default.events
VALUES
(1, 1001, 'United States', 'click'),
(2, 1002, 'United Kingdom', 'view'),
(3, 1003, 'Germany', 'click'),
(4, 1004, 'Netherlands', 'view');
使用 iceberg_metadata 函数验证分区效果:
SELECT file_path, record_count
FROM iceberg_metadata(my_datalake.default.events)
WHERE content = 'EXISTING';
更新和删除操作在 bucket/truncate 分区表上同样受支持,采用 merge-on-read 语义和位置删除。
四、Iceberg Schema Properties 管理
功能概述
Iceberg 目录允许在模式(Schema/Namespace)级别附加任意的键值属性。这些属性通常用于记录所有权信息、描述、默认存储位置或其他适用于同一 Schema 下所有表的元数据。
v1.5.3 提供了三个新的表函数来管理 Schema 属性:
| 函数名 | 功能 |
|---|---|
set_iceberg_schema_properties | 设置 Schema 属性 |
iceberg_schema_properties | 读取 Schema 属性 |
remove_iceberg_schema_properties | 删除 Schema 属性 |
代码示例
-- 设置 Schema 属性
CALL set_iceberg_schema_properties(my_datalake.default, {
'owner': 'analytics-team',
'description': 'Default analytics schema'
});
-- 读取 Schema 属性
SELECT * FROM iceberg_schema_properties(my_datalake.default);
┌─────────────┬──────────────────────────┐
│ key │ value │
│ varchar │ varchar │
├─────────────┼──────────────────────────┤
│ owner │ analytics-team │
│ description │ Default analytics schema │
└─────────────┴──────────────────────────┘
-- 删除 Schema 属性
CALL remove_iceberg_schema_properties(
my_datalake.default,
['description']
);
Schema 属性通过 Iceberg REST Catalog 写入,任何连接到同一 Catalog 的 Iceberg 引擎都能立即看到更新。返回值为剩余的 Schema 属性数量。
五、Iceberg V3 格式支持
V3 新特性
Iceberg V3 规范引入了多项重要新特性,DuckDB-Iceberg 现在对以下功能同时支持读写:
| 特性 | 说明 |
|---|---|
VARIANT 数据类型 | 半结构化数据支持,类似 JSON |
TIMESTAMP_NS 数据类型 | 纳秒级时间戳 |
| Schema 级默认值 | 列的默认值定义 |
| 二进制删除向量 | 比 V2 的位置删除文件更紧凑 |
| 行血统追踪 | 数据行来源追踪 |
其中最具实际意义的是二进制删除向量。在 V2 表中,删除操作写入 Parquet 格式的位置删除文件;在 V3 表中,同样的信息以更紧凑的二进制格式编码为 Puffin 文件。DuckDB 会根据表的 format-version 自动选择正确的格式。
代码示例
-- 创建 V3 表
CREATE TABLE my_datalake.default.v3_table
WITH ('format-version' = 3) AS
FROM (VALUES
(1, {'kind': 'click', 'x': 10}::VARIANT, TIMESTAMP_NS '2026-05-20 12:00:00.123456789'),
(2, {'kind': 'view'}::VARIANT, TIMESTAMP_NS '2026-05-20 12:00:00.987654321')
) t(id, payload, event_time);
-- 删除(V3 表使用二进制删除向量)
DELETE FROM my_datalake.default.v3_table
WHERE id = 1;
SELECT * FROM my_datalake.default.v3_table;
┌───────┬──────────────────┬───────────────────────────────┐
│ id │ payload │ event_time │
│ int32 │ variant │ timestamp_ns │
├───────┼──────────────────┼───────────────────────────────┤
│ 2 │ {"kind": "view"} │ 2026-05-20 12:00:00.987654321 │
└───────┴──────────────────┴───────────────────────────────┘
使用 iceberg_metadata 验证删除向量的格式:
SELECT manifest_content, content, file_format
FROM iceberg_metadata(my_datalake.default.v3_table);
┌──────────────────┬──────────────────┬─────────────┐
│ manifest_content │ content │ file_format │
│ varchar │ varchar │ varchar │
├──────────────────┼──────────────────┼─────────────┤
│ DATA │ EXISTING │ parquet │
│ DELETE │ POSITION_DELETES │ puffin │
└──────────────────┴──────────────────┴─────────────┘
注意:
GEOMETRY类型和Unknown类型目前尚未在 DuckDB-Iceberg 中支持,团队计划在 DuckDB v2.0.0 中添加。
六、与传统方案的对比
| 特性 | DuckDB-Iceberg v1.5.3 | Apache Spark + Iceberg | Trino + Iceberg |
|---|---|---|---|
| 部署复杂度 | 嵌入式,无需集群 | 需要 Spark 集群 | 需要 Trino 集群 |
| 查询启动时间 | 毫秒级 | 秒级(需启动 Executor) | 秒级 |
| MERGE INTO | ✅ 完整支持 | ✅ 完整支持 | ✅ 完整支持 |
| ALTER TABLE | ✅ 完整支持 | ✅ 完整支持 | ✅ 完整支持 |
| V3 格式 | ✅ 读写支持 | ✅ 读写支持 | ⚠️ 部分支持 |
| bucket/truncate | ✅ 写入 + 读取 | ✅ 完整支持 | ✅ 完整支持 |
| Schema Properties | ✅ 完整管理 | ✅ 完整管理 | ✅ 读取支持 |
| VARIANT 类型 | ✅ V3 支持 | ❌ 原生不支持 | ❌ 原生不支持 |
| 安装大小 | ~50MB | 数 GB | 数百 MB |
| 单机海量数据处理 | ✅ 优秀(列式向量化) | ⚠️ 需要分布式 | ⚠️ 需要分布式 |
| Python 集成 | ✅ 原生支持 | ✅ PySpark | ❌ 需 JDBC |
DuckDB-Iceberg 的最大优势在于嵌入式架构带来的低延迟体验。不需要启动任何集群,一条 ATTACH 命令即可连接到 Iceberg REST Catalog,然后用熟悉的 SQL 进行查询和写入。
七、未来路线图
根据官方博客,DuckDB-Iceberg 的后续开发重点包括:
UPDATE、DELETE、MERGE的更多优化:进一步提升写入性能- DuckDB v2.0.0 中的 GEOMETRY 类型支持:补全 Iceberg 类型支持
- 更深度的 Quack 协议集成:通过 Quack 远程访问 Iceberg 表
- DuckLake 中基于 Iceberg 的 Catalog 支持:统一湖仓管理
八、变现建议
DuckDB-Iceberg v1.5.3 的新特性为数据团队提供了多种变现路径:
1. 构建轻量级数据湖仓查询服务 利用 DuckDB 的嵌入式特性,为中小团队提供替代 Spark/Trino 的轻量级 Iceberg 查询方案。按查询量或并发用户数收费,月费 $500-$2000/团队。
2. 数据管道自动化工具
基于 MERGE INTO 和 ALTER TABLE 构建自动化 ETL/ELT 工具,帮助企业管理 Iceberg 表的增量更新和模式演化。SaaS 订阅模式,$200-$800/月。
3. 培训和咨询 围绕 DuckDB-Iceberg 的最佳实践、性能调优和架构设计提供企业培训。单次工作坊 $3000-$8000。
4. 开源周边工具开发 开发 DuckDB-Iceberg 的管理 UI、监控面板或 CI/CD 集成工具,通过开源社区版 + 企业版(含高级功能)变现。
5. 云原生数据湖管服务 在 AWS/GCP/Azure 上部署基于 DuckDB-Iceberg 的托管查询服务,利用 Serverless 架构实现成本优势,预留给客户的利润空间约 30-50%。
总结
DuckDB v1.5.3 中的 Iceberg 扩展更新是里程碑式的。MERGE INTO 提供了原子化的 Upsert 语义,ALTER TABLE 解除了模式演化的限制,bucket/truncate 分区变换带来了更灵活的数据布局策略,而 Iceberg V3 支持则将 DuckDB 推向了湖仓技术的最前沿。
对于数据工程师和架构师来说,这意味着可以用一个不到 50MB 的嵌入式数据库,完成过去需要分布式集群才能实现的 Iceberg 管理工作。无论是本地开发、CI/CD 测试还是小规模生产环境,DuckDB-Iceberg 都是一个极具吸引力的选择。
立即升级到 DuckDB v1.5.3,体验这些新特性吧!
