alitrack

Parquet Variant × DuckDB:列存半结构化数据的正确打开方式(下)

Parquet Variant × DuckDB:列存半结构化数据的正确打开方式

本文为上篇《Parquet Variant × DuckDB:列存半结构化数据的正确打开方式》的下篇,继续讨论实战建议、生态对比与总结。

实战建议:双层存储

如果你打算在生产中使用 Variant,推荐"双层存储"模式。

1原始层(Variant)         提取层(STRUCT)
2┌──────────────┐         ┌────────────────┐
3│ raw_events   │         │ core_events    │
4│ ├─ id        │  ───→  │ ├─ id          │
5│ └─ payload   │  (ETL) │ ├─ event       │
6│   (VARIANT)  │         │ ├─ user_id     │
7└──────────────┘         │ ├─ timestamp   │
8                         │ └─ payload     │  ← 保留原始
9                         │   (VARIANT)    │
10                         └────────────────┘
1-- 原始层:直接接收动态 schema 数据
2CREATE TABLE raw_events AS
3SELECT * FROM read_parquet('logs/*.parquet');
4
5-- 提取层:高频字段物化为静态列
6CREATE TABLE core_events AS
7SELECT
8    id,
9    payload.event::VARCHAR AS event,
10    payload.user::INTEGER  AS user_id,
11    payload.ts::TIMESTAMP  AS timestamp,
12    payload  -- 保留完整 Variant 以便未来提取新字段
13FROM raw_events;
14
15-- 或者用 GENERATED 列
16CREATE TABLE events_v2 (
17    id INTEGER,
18    payload VARIANT,
19    event VARCHAR GENERATED ALWAYS AS (payload.event::VARCHAR),
20    user_id INTEGER GENERATED ALWAYS AS (payload.user::INTEGER)
21);

这么做的好处是:原始层享受 Variant 的写入灵活性和 schema 弹性,提取层享受 STRUCT 的极致查询性能。

生态支持

Variant 的跨引擎互操作已经形成共识:

引擎/平台支持状态
Apache Spark 4.0✅ 读写 + shredding
Snowflake✅ 原生,原生
DuckDB v1.5+✅ 全链路
Delta Lake✅ 官方协议
Apache Iceberg v3✅ 扩展类型
parquet-java✅ 参考实现 1.16.0
Arrow C++ / cuDF / Polars❌ 待支持

DuckDB 可以直接读取 Snowflake 产生的 shredded Variant Parquet,v1.5.3+ 可读 Iceberg V3 的 Variant 列。这意味着一份 Variant 数据可以在 Snowflake、Spark、DuckDB 之间自由流转。

总结

Parquet Variant 不是银弹,但对于处理动态 schema 数据的团队来说,它是目前最正确的方向。
它在理念上解决了 JSON 字符串的四个根本问题:

  • 查询时不需要重新 parse
  • 类型信息在写入时就保留
  • 字段名不重复存储
  • 支持列式优化(shredding、剪枝、下推)

DuckDB 的集成速度很快——从首个 PR 到发布只用了 8 个月。v1.5 阶段的实现"可用但偏早期",v1.6 的原生 Variant 类型和性能优化值得期待。
如果你面对的是日志分析、API 数据湖、事件流处理这类动态 schema 场景,现在就可以用"双层存储"模式上车。高频查询走提取列,灵活查询走原始 Variant。两全其美。

格式层面最好的半结构化类型,引擎层面最快的 OLAP 分析引擎——Variant × DuckDB 是 2026 年数据工程领域最具影响力的组合之一。不是因为它完美,而是因为它十年来第一次给出了一个"正确"的答案。