Featured image of post DuckDB-Iceberg v1.5.3 新特性详解:MERGE INTO、ALTER TABLE 与 Iceberg V3 全面支持

DuckDB-Iceberg v1.5.3 新特性详解:MERGE INTO、ALTER TABLE 与 Iceberg V3 全面支持

DuckDB v1.5.3 中 DuckDB-Iceberg 扩展迎来重大更新:完整支持 MERGE INTO 合并写入、ALTER TABLE 架构演进、bucket/truncate 分区变换、Iceberg V3 规范以及 Schema Properties。本文深入解析所有新特性并提供可执行 SQL 示例。

引言

2026年5月20日,DuckDB 发布了 v1.5.3 补丁版本,同时推出了 DuckCon #7 阿姆斯特丹大会。虽然 v1.5.3 核心版本的更新主要集中在 bug 修复上,但伴随发布的 DuckDB-Iceberg 扩展 带来了令人瞩目的新功能——这被官方称为"Iceberg 写入门系列博客的第二部分"。

在 v1.4 时代,DuckDB 对 Iceberg 的支持主要集中在读取能力上。从 v1.5.0 的 DuckLake v1.0 标准到 v1.5.3,DuckDB-Iceberg 已经从一个"读扩展"蜕变为功能完备的湖格式写入引擎

本文将深入剖析 v1.5.3 中 DuckDB-Iceberg 的所有核心新特性,并通过完整的 SQL 示例帮助你快速上手。

一、DuckDB-Iceberg 快速入门

在使用新特性之前,首先需要连接到你的 Iceberg REST Catalog。DuckDB-Iceberg 支持多种目录后端:

  • Apache Polaris — Apache 基金会推荐的统一目录服务
  • Lakekeeper — 高性能云原生 Iceberg 目录
  • Amazon S3 Tables — AWS 原生的 S3 表格支持

连接命令如下:

ATTACH 'warehouse_name' AS my_datalake (
    TYPE iceberg,
    other options
);

连接成功后,你就可以使用标准的 SQL 语法操作 Iceberg 表了,无需学习新的 API。

二、MERGE INTO 完整支持 —— 湖格式 UPSERT 的终极方案

DuckDB 的 MERGE INTO 语句是处理 UPSERT(插入或更新)操作的推荐方式。对于 Iceberg 这类没有主键约束的湖格式表,MERGE INTO 尤为重要。

2.1 基本用法

-- 创建目标表
CREATE TABLE my_datalake.default.people (
    id INTEGER,
    name VARCHAR,
    salary FLOAT
);

INSERT INTO my_datalake.default.people
    VALUES (1, 'John', 92_000.0), (2, 'Anna', 100_000.0);

结果:

┌───────┬─────────┬──────────┐
│  id   │  name   │  salary  │
│ int32 │ varchar │  float   │
├───────┼─────────┼──────────┤
│     1 │ John    │  92000.0 │
│     2 │ Anna    │ 100000.0 │
└───────┴─────────┴──────────┘

2.2 执行 UPSERT 操作

MERGE INTO my_datalake.default.people AS target
    USING (
        FROM (VALUES
            (1, 'John', 105_000.0),
            (3, 'Sarah', 95_000.0)
        ) t(id, name, salary)
    ) AS upserts
    ON (upserts.id = target.id)
    WHEN MATCHED THEN UPDATE
    WHEN NOT MATCHED THEN INSERT;

查询结果:

┌───────┬─────────┬──────────┐
│  id   │  name   │  salary  │
│ int32 │ varchar │  float   │
├───────┼─────────┼──────────┤
│     1 │ John    │ 105000.0 │
│     2 │ Anna    │ 100000.0 │
│     3 │ Sarah   │  95000.0 │
└───────┴─────────┴──────────┘

2.3 合并删除操作

MERGE INTO 还可以在同一条语句中包含删除逻辑:

MERGE INTO my_datalake.default.people AS target
    USING (VALUES (1, NULL, NULL)) AS src(id, name, salary)
    ON (src.id = target.id)
    WHEN MATCHED THEN DELETE;

底层实现上,MERGE INTO 使用 Merge-on-Read(MoR) 语义,对于 UPDATEDELETE 操作会写入位置删除文件(positional deletes),不会重写整个数据文件。

三、ALTER TABLE —— 告别静态表架构

在 v1.4 中,Iceberg 表的架构演进是一个文档化但尚未实现的限制。v1.5.3 填补了这一空白,支持了最常见的架构操作。

3.1 完整操作示例

-- 创建表
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;

-- 设置格式版本
ALTER TABLE my_datalake.default.renamed_table
    SET ('format-version' = 3);

3.2 工作原理

每次 ALTER TABLE 操作都会更新 Iceberg 表的 current-schema-id。由于 Iceberg 的架构演进是纯元数据操作,不需要重写任何数据文件,因此速度极快,对查询性能无影响。

变更会立即对其他连接该目录的 Iceberg 感知引擎可见。

四、Partition Transforms —— bucket 与 truncate 支持

Iceberg 规范定义了多种分区变换(Partition Transforms),决定了数据文件在磁盘上的布局方式。v1.5.3 新增了对 buckettruncate 变换的支持。

4.1 Bucket 变换

bucket(N, col) 将列的值哈希到 N 个桶中,适合高基数列的稳定分区

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');

4.2 Truncate 变换

truncate(W, col) 根据前 W 个字符(或数值列向下舍入到 W 的倍数)分组,适合前缀分区场景。

4.3 验证分区效果

SELECT file_path, record_count
FROM iceberg_metadata(my_datalake.default.events)
WHERE content = 'EXISTING';

更新和删除操作对 bucket/truncate 分区表同样支持,底层同样使用位置删除文件。

五、Iceberg Schema Properties —— 命名空间级别元数据管理

Iceberg 目录允许在命名空间(Schema)级别附加任意键值对属性。这些属性通常用于记录所有权、描述信息、默认存储位置等。

5.1 核心函数

DuckDB-Iceberg v1.5.3 提供了三个专用函数:

函数功能
iceberg_schema_properties(ns)读取命名空间属性
set_iceberg_schema_properties(ns, props)设置/更新属性
remove_iceberg_schema_properties(ns, keys)删除指定属性

5.2 使用示例

-- 设置命名空间属性
CALL set_iceberg_schema_properties(my_datalake.default, {
    'owner': 'analytics-team',
    'description': 'Default analytics schema'
});

-- 查看属性
SELECT * FROM iceberg_schema_properties(my_datalake.default);
┌─────────────┬──────────────────────────┐
│     key     │          value           │
│   varchar   │         varchar          │
├─────────────┼──────────────────────────┤
│ owner       │ analytics-team           │
│ description │ Default analytics schema │
└─────────────┴──────────────────────────┘
-- 删除属性
CALL remove_iceberg_schema_properties(
    my_datalake.default,
    ['description']
);

属性通过 Iceberg REST Catalog 写入,其他 Iceberg 感知引擎可以立即看到更新。

六、Iceberg V3 规范支持 —— 下一代湖格式

Iceberg v3 规范引入了多项重大改进,DuckDB-Iceberg v1.5.3 已全面支持读取和写入 V3 表。

6.1 V3 核心特性

特性说明
VARIANT 类型原生支持半结构化数据存储
TIMESTAMP_NS 类型纳秒级时间戳精度
列级默认值Schema 级别定义列的默认值
二进制删除向量使用 Puffin 格式替代 Parquet 删除文件
行血缘追踪追踪数据行来源

6.2 二进制删除向量

这是 V3 最重要的改进之一。 在 V2 表中,DuckDB-Iceberg 将删除操作写为 Parquet 文件;在 V3 表中,同样的信息被编码为更紧凑的二进制删除向量(Puffin 文件)

-- 创建 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 │
└───────┴──────────────────┴───────────────────────────────┘

通过元数据查询可以看到删除以 Puffin 格式写入:

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      │
└──────────────────┴──────────────────┴─────────────┘

DuckDB 会根据表的 format-version 自动选择正确的写入格式。

七、与传统工具对比

特性DuckDB-Iceberg v1.5.3Apache SparkDelta Lake (Spark)AWS Glue
部署复杂度⭐ 无需集群⭐⭐⭐⭐⭐ YARN/K8s⭐⭐⭐⭐⭐ Spark 集群⭐⭐⭐⭐ 云管理
MERGE INTO✅ 完整支持✅ DataFrame API✅ 完整支持⚠️ 有限
ALTER TABLE✅ 架构演进⚠️ 需重写✅ 完整支持⚠️ 有限
分区变换✅ bucket/truncate✅ 所有变换✅ 所有变换⚠️ 有限
V3 支持✅ 读写⚠️ 部分⚠️ 部分
二进制删除向量✅ Puffin
Schema Properties✅ 原生函数⚠️ API⚠️ Delta 属性
查询性能⭐⭐⭐⭐⭐ 原生优化⭐⭐ 启动开销⭐⭐ 启动开销⭐⭐ 云延迟
学习曲线⭐ SQL 直写⭐⭐⭐ DataFrame⭐⭐⭐ Spark SQL⭐⭐⭐ 控制台

八、变现建议

8.1 数据服务产品线

利用 DuckDB-Iceberg 的低运维成本特性,你可以构建以下高利润数据服务

  1. 企业级数据湖托管服务 — 为客户部署和管理 Iceberg 数据湖,利用 DuckDB 的零运维特性将成本控制在 Spark 方案的 30% 以下
  2. 实时数据同步 SaaS — 基于 MERGE INTO 的 Upsert 能力,构建面向电商/金融的实时数据同步管道
  3. 数据湖迁移咨询 — 帮助企业从传统 Hive/Parquet 迁移到 Iceberg V3,利用 DuckDB 的兼容性实现无损迁移

8.2 技术栈组合建议

业务场景DuckDB + Iceberg +目标客户
实时数据湖Debezium + Kafka电商平台
BI 分析层Metabase/Superset中小企业
AI 数据管道DuckDB-Variant + LanceAI 初创公司
数据治理Apache Polaris + Ranger金融机构

8.3 变现路线图

Phase 1 (0-3月): 搭建技术 Demo + 技术博客引流
    └── 发布 DuckDB-Iceberg 系列教程,积累 SEO 流量

Phase 2 (3-6月): 推出标准化数据湖解决方案
    └── 基于 DuckDB-Iceberg 部署方案的产品化

Phase 3 (6-12月): 构建数据湖管理平台 SaaS
    └── 将 DuckDB-Iceberg 的管理操作封装为 Web 平台

结论

DuckDB v1.5.3 中的 DuckDB-Iceberg 扩展已经从一个"读取优先"的扩展,进化为功能全面的湖格式写入引擎MERGE INTOALTER TABLEbucket/truncate 分区变换、V3 规范支持以及 Schema Properties 等功能,填补了此前与 Spark/Delta 生态的关键差距。

随着 DuckLake v1.0 标准的正式发布和 Quack 客户端-服务器协议的推出,DuckDB 正在构建一个完整的自托管湖仓一体生态。对于追求低运维成本和高查询性能的团队来说,DuckDB-Iceberg 已经是一个成熟的选择。

⚠️ 注意:GEOGRAPHYUNKNOWN 类型目前在 DuckDB-Iceberg 中尚未支持,计划在 DuckDB v2.0.0 中添加。

如果你希望在特定功能上获得优先级支持,可以在 DuckDB-Iceberg GitHub 仓库 提交 Issue,或直接联系 DuckLabs 的技术团队。

DuckDB-Iceberg v1.5.3 架构图

📺 Watch video tutorials → DuckDB Lab YouTube

Subscribe for more DuckDB & AI automation tutorials

使用 Hugo 构建
主题 StackJimmy 设计