Parquet Variant 正式成为开放标准
存 JSON 的日子到头了?Parquet Variant 正式成为开放标准
30x 查询加速、跨引擎互通、21 种原生类型——这些都不是 PPT
一、数据工程师的「三体问题」
如果你处理过半结构化数据,你一定经历过这种纠结:
1事件日志,每天几亿条,schema 三天一变存成文本 JSON?
灵活是真灵活,但查一个字段要全量解析整条数据。一天几亿条,每条都解析一遍,存储和计算成本吃不住。
先拍平再存成结构化表?
查询是快了,但加个字段要改 schema、重新建表、重跑 ETL。领导周一加了个新字段,你周五还没改完。更糟糕的是,日志里不同事件类型各有各的结构,拍平成一堆 nullable 列之后,schema 又宽又稀。
用 JSONB?
PostgreSQL 的 JSONB 确实比纯文本快。但有一个根本问题——JSONB 是私有格式。数据进了 JSONB 就锁在 PG 里,走不出数据库。你元数据用 Hive,计算用 Spark,存 PG 不是不行,但你得读出来再写回 Parquet——多了一层搬运。
这不只是选存储的问题。这是数据领域的「三体问题」:
1灵活 ↔ 高效 ↔ 开放,三者不可兼得三选二容易,三个都要几乎不可能。
直到 2026 年 2 月,Apache Parquet 社区正式批准了一个新类型——Variant。
二、Variant 是什么?
Variant 是 Parquet 的一种原生逻辑类型,专门为半结构化数据设计。它不是 JSON 的变体,而是一种自描述的二进制编码格式。
在 Parquet 文件中,Variant 存储为一个包含两个 binary 字段的结构体:
1optional group event_data (VARIANT(1)):
2 required binary metadata → 字段名字典 + 类型信息(不重复存储)
3 required binary value → 实际数据(通过偏移量导航)
这意味着什么?
字段名不重复。JSON 里 "timestamp" 字符串每行都出现一次;Variant 在 metadata 字典里存一次,每行用整数 ID 引用。对几百列的大 JSON,这能省下一个数量级的存储。
偏移量导航替代全量解析。查 order.item.name 时,Variant 直接跳到对应偏移位置,不需要读整条数据。这在分析场景下是量级的差异——如果你只查 5 个字段,你就只读那个位置的比特,其他字段完全不碰。
类型不丢。JSON 只有字符串/数字/布尔/对象/数组五种类型。Variant 支持完整的数据类型体系:
| 类别 | 类型 |
|---|---|
| 整数 | int8 / int16 / int32 / int64 |
| 浮点 | float / double |
| 时间 | date / time / timestamp / timestamptz |
| 精确数值 | decimal4 / decimal8 / decimal16 |
| 其他 | uuid, binary, string, boolean, null |
重点是 timestamp、date、decimal、uuid——这些在 JSON 里只能存成字符串,查的时候还得来回转换。
三、Shredding:30x 加速的秘密武器
Variant 有一个很巧妙的设计——Shredding(分片存储)。
简单说,Shredding 会自动把 Variant 里最常访问的字段提取出来,存成强类型的独立 Parquet 列。
1# 原始 Variant(不分片)
2optional group event_data (VARIANT(1)):
3 required binary metadata
4 required binary value # 整个 JSON blob
5
6# 分片后的 Variant
7optional group event_data (VARIANT(1)):
8 required binary metadata
9 optional binary value # 剩余未分片的部分
10 optional int32 typed_value.userId # userId 提成 INT32 列
11 optional binary typed_value.eType # eType 提成字符串列
分片之后,WHERE userId = 100 直接走 INT32 列的谓词下推,Variant blob 完全不用碰。
Databricks 的公开 benchmark 数据:
| 存储方式 | 读取性能 |
|---|---|
| JSON 字符串(基线) | 1x |
| Variant(不分片) | 8x 更快 |
| Variant + Shredding | 30x 更快 |
写的代价呢?比纯 JSON 字符串慢 20%-50%——但 Databricks 的结论是:分析场景下,写入慢一点、查询快 30x,值。
四、Variant vs JSONB:本质差异
我见过有人把 Variant 叫做 "Parquet 版的 JSONB"。这个类比不准确,而且恰恰模糊了最重要的区别。
| 维度 | PostgreSQL JSONB | Parquet Variant |
|---|---|---|
| 格式 | 私有 | 开放标准 |
| 互通性 | 锁在 PG | Spark/DuckDB/Snowflake 都能读 |
| 存储 | 行存 + TOAST | 列存 + 压缩 + Shredding |
| 字段名去重 | ❌ 每行重复 | ✅ metadata 字典 |
| 谓词下推 | 有限(GIN 索引) | ✅ (通过 Shredded 列) |
| 类型系统 | JSON 基本类型 | 21 种,含 timestamp/decimal/uuid |
核心差异不是技术实现——一个把数据锁起来,一个把数据解放出来。
JSONB 是单机数据库内部格式。数据进了 JSONB,要拿出来做跨系统分析,你就得把它导出成 Parquet,这个过程就叫 ETL。ETL 是成本,不是功能。
Variant 是 Parquet 的原生类型。同一个文件,DuckDB 可以读,Spark 可以读,Snowflake 可以读,Databricks 可以读。不需要 ETL。
这就是为什么各大引擎跟进得这么快:
| 组件 | 状态 |
|---|---|
| Parquet 格式规范 | ✅ 2.12.0 正式发布 |
| Delta Lake | ✅ 支持超过一年 |
| Apache Iceberg v3 | ✅ 2025 年 5 月批准 |
| Apache Spark 4.0 | ✅ 原生 VariantType |
| DuckDB | ✅ 原生 VARIANT 类型 + Shredding |
| Snowflake | ✅ 原生 VARIANT(最早的源头) |
| 实现 | ✅ Java / Rust / Go |
Databricks 向 parquet-java 贡献了 9,600 行代码。Apache Iceberg v3 把 Variant 写进了表格式规范。DuckDB 直接支持 Variant 的读写和 Shredding。
五、对数据工程师意味着什么
读完技术细节,落地到日常工作。Variant 会改变什么?
不需要再跟 schema 打架了。
IoT 数据,同一张表里可以既有温度传感器字段(temp/unit/battery),又有运动传感器字段(motion_detected/confidence/zone)。不用提前定义哪个传感器长什么样,也不用为了兼容做宽表噩梦。
日志分析可以告别 JSON 字符串了。
之前存事件日志,要么存字符串查不动,要么先 ETL 成结构化表再查。现在直接写 Variant 列,常用字段靠 Shredding 自动提列,少用的留在 Variant 里。一步到位。
数据不再需要搬来搬去了。
同一个 Parquet 文件,Spark 做批量处理,DuckDB 做交互式查询,Snowflake 做报表。数据在 Parquet 里,不需要复制一份去适配每个引擎的格式。
Snowflake 的 VARIANT 是最早的灵感来源。而 Parquet Variant 比 Snowflake 更进一步——它定义了开放的二进制编码规范,任何引擎都可以实现。这也意味着它正在走向数据湖的主流地位。
六、不是替代品,是基础设施升级
Variant 不会消灭 JSON。JSON 作为交换格式(API 响应、配置文件)会继续存在。
Variant 消灭的是把 JSON 字符串当存储格式这个不好的习惯——就像 Parquet 消灭了 CSV 作为分析存储格式一样。
它解决的不是"存什么",而是"怎么存"的问题。同样的 JSON 数据,用 Variant 存,比用字符串存更快、更省、更好查。而且数据还在 Parquet 里,跟整个湖仓生态相容。
如果你正在建新的数据管道,或者有半结构化数据的存储/查询痛点,这可能是 2026 年最值得关注的基础设施升级之一。
参考
- Apache Parquet 官方公告: parquet.apache.org/blog/2026/02/27/variant-type-in-apache-parquet-for-semi-structured-data/
- Databricks Blog: Introducing Variant — A New Open Standard (2026.02)
- Variant 编码规范: github.com/apache/parquet-format/blob/master/VariantEncoding.md
- DuckDB Variant 文档: duckdb.org/docs/current/sql/data_types/variant.html
- Apache Iceberg v3 规范: iceberg.apache.org/spec/#version-3