摘要:随着数据不断演进,尤其在 AI Agent、LLMOps 与可观测性系统快速发展的背景下,宽 JSON 的字段膨胀带来巨大的性能挑战。Apache Doris 4.1 通过 Doc Mode 与 Segment V3 实现了高效的存储与查询优化,使系统在写入吞吐、查询性能与资源开销之间保持良好平衡,其综合性价比优于 Clickhouse、PostgreSQL 等业界典型方案。
随着业务持续演进(车型上线、埋点变更、模型升级),系统不断引入新的字段,导致字段集合快速膨胀。当字段并集达到万级、单行数据高度稀疏且查询需求频繁变化时,传统的预定义 Schema 已难以满足需求。典型特征包括:字段规模从数百到上万不等,演进速度快、分布分散、写入吞吐量高,同时查询往往只关注少数字段。
典型应用场景如下:
- 车联网:车型、硬件与 OTA 更新叠加,字段随设备与版本频繁变化,规模可达万级,且车型间差异显著。
- 可观测性:微服务与 SDK 持续迭代,日志与 Trace 维度不断扩展至数百至上千字段。
- 行为分析:业务扩张带来属性变宽,成熟阶段字段规模约 1k~5k。
- AI 应用:Prompt 与模型快速迭代,Agent Trace、Tool 调用、RAG 检索结果及评估数据持续引入新 Key,字段结构随模型与工作流变化不断演进。
面对这些问题,Apache Doris 4.1 提供了针对性的解决方案,通过 Doc Mode 和 Segment V3 等优化特性,有效提升了系统在这些场景中的性能、扩展性和稳定性。
1. 核心性能瓶颈
随着吞吐量持续攀升,当 JSON path 扩展到万级时,系统主要面临两个核心瓶颈:
- 元数据膨胀:随着列/字段规模的增长,元数据(如 Footer 和 metadata)的体积会随列数线性增长,导致系统存储压力骤增。这不仅仅是个别现象,而是列式存储普遍面临的挑战。
- 过早子列物化:为了提升查询性能,一些系统(如早期的 Doris Variant 默认实现和 Elasticsearch 等)会在写入时将每个 JSON path 立即物化为独立列。这种做法会带来写入和 Compaction 的双重压力。
在 AI 场景下,由于 Prompt、Tool 与 Trace 数据演化速度更快,字段规模和冷热变化往往比传统埋点系统更加明显。不仅如此,这两个问题往往在实际场景中相互叠加——写入瓶颈导致文件碎片增多,而文件碎片又进一步加剧元数据膨胀,形成恶性循环。
2. 常见的解决方案
在应对万级以上宽 JSON 的挑战时,不同系统给出了各具侧重的技术路径,但本质上都在 灵活性、写入成本与查询性能 三者之间做权衡。

参考链接
- Making complex JSON 58x faster, use 3,300x less memory, in ClickHouse
- Mapping explosion | Elastic Docs
- The Apache Iceberg™ Variant Type: Flexible Semistructured Data, Reimagined
- 深入理解 Doris Variant:如何让 JSON 查询性能追平列存,还能承载万列索引字段?|Deep Dive
- parquet-format/VariantShredding.md at master · apache/parquet-format
我们选取 ClickHouse 的 Advanced Serialization 与 PostgreSQL 的 JSONB 两种具有代表性的方案进一步分析。
2.3 ClickHouse:控制列数但编码效率受限
ClickHouse v25.8 引入了 Advanced Shared Data 序列化格式(参考 Making complex JSON 58x faster),用于缓解 JSON path 过多时导入性能急剧下降的问题。这一方案通过固定的 bucket 数控制文件总数,避免了列数多时完全不可用的问题。
这一方案在可用性上做了明显改善,但也带来了新的代价:受 ClickHouse 类 PAX(Partition Attributes Across)存储布局实现机制的影响,数据按列或属性被分散组织,查询时往往需要在多个存储位置之间反复定位和跳转,从而导致随机读放大;同时,为了兼顾写入与合并流程,系统还需要额外保留一份原始数据副本,进一步推高存储成本。整体来看,问题虽然得到一定缓解,但在大规模场景下,查询性能和资源开销仍然不够理想。
2.4 PostgreSQL:文档友好但分析场景受限
PostgreSQL 的 JSONB 类型将 JSON 解析为二进制格式存储,支持 GIN 索引做键值检索。在点查和文档回读(SELECT*)场景下,JSONB 表现出色——原始文档不需要从大量子列中重新拼接。
但其本质仍是行式存储,缺乏列式优化。在分析场景(如按字段过滤、聚合)下,即使只查询单个 key,也需逐行解析 JSON,难以利用列式带来的压缩与计算优势,随着数据规模增长,查询延迟会显著上升。
3. Doris 4.1:延迟物化 + 按需加载
针对上述问题,Apache Doris 在最新发布的 4.1 版本中引入了 Doc Mode 与 Segment V3 两项关键能力,分别从写入路径与元数据管理两个层面进行优化:
- Doc Mode(延迟子列物化):在写入阶段以文档形态高效落盘,仅在 Compaction 阶段按需物化高频 JSON path,从而显著降低写入放大与系统压力,提升整体吞吐能力。
- Segment V3(按需加载元数据):将原本集中在 Footer 中的列级元数据拆分为独立存储结构,查询时仅加载相关列的元数据,在万列规模下有效降低内存占用与 I/O 开销。
两者结合,使 Doris 在 写入吞吐、查询延迟与元数据管控 三个关键维度上实现了更均衡的表现。
那么,相较于业界典型方案 ClickHouse 和 PostgreSQL,Doris 是否更具优势?
从机制上看:
- 对比 ClickHouse:Doris 在子列物化后采用纯列式连续存储,避免了类似 PAX 布局带来的随机读放大问题;同时在默认策略下无需保留冗余副本,存储开销更可控。
- 对比 PostgreSQL(JSONB):一旦 JSON path 被物化,Doris 即可充分发挥列式存储在压缩与向量化计算方面的优势;而 JSONB 始终受限于行式存储模型,其 I/O 模式在分析场景下存在天然瓶颈。
在基准测试中(万级 JSON path、1 亿行数据、单机 16C / 64GB / SSD,详见后文《综合性能验证》):
- Doris vs ClickHouse:在宽 JSON 的聚合与过滤场景中,Doris 查询延迟稳定在百毫秒级;而 ClickHouse 受 Advanced 编码带来的随机读影响,查询延迟上升至数秒级。同时,在默认配置下,Doris 的存储空间约为 ClickHouse 的 60%。

- Doris vs PostgreSQL:PostgreSQL 在文档整行回读(如 Q3)场景中表现突出;但在聚合与过滤场景(Q1 / Q2)下,其查询延迟相较 Doris 存在数量级差距,可达数百倍。

4. Doc Mode:按需延迟子列物化
在 Doris 4.1 中,Doc Mode 将写入、合并与查询解耦为三个阶段处理,从而在保证写入吞吐的同时,查询性能的渐进优化:
- 写入阶段,仅以文档形态存储 JSON
- 合并阶段(Compaction):在合适时机按需将高频 path 物化为子列
- 查询阶段:根据字段的物化状态,自动选择最优执行路径
4.1 写入阶段:优先把 JSON keys 编码落盘为 Hash Sharded

为优先保障写入吞吐,系统将 JSON 数据编码为 Sharded Map,以哈希分片的方式进行结构化落盘。这一设计既支持 SELECT * 的高效整行返回,也为未物化字段提供统一的兜底存储。
原始 JSON 被拆分到多个独立的列式 Map<Binary, Binary> 分片中,并通过variant_doc_hash_shard_count参数控制分片数量,使数据均匀分布。
在查询 fallback 场景下,仅需命中并扫描对应的单一分片,避免全量数据扫描带来的性能开销。由此,写入复杂度从“随未知 Path 数量增长”转变为“面向固定分片结构”,显著提升系统稳定性与可扩展性。
4.2 合并阶段:推迟物化
参数 variant_doc_materialization_min_rows用于定义 path 的物化时机:当数据批次较小或尚未沉淀时,仅写入 Sharded Map;只有在触发 Compaction 且行数达到阈值后,才会将高频 path 抽取为独立子列。相比即时列化,这种延迟决策机制显著提升了突发写入场景下的系统稳定性。

图 3:写入先落 Doc Map,Compaction 阶段再把常用字段抽成列。
4.3 查询阶段:三档读路径的自动切换
对于上层查询引擎而言,Doc Mode 会根据字段的物化状态,将请求自动路由到最合适的读取路径,实现性能与灵活性的动态平衡:
DOC Materialized:热点字段已被抽取为子列,直接走纯列式读取路径,查询效率最高,同时可充分利用索引下推等优化能力。DOC Map:用于SELECT *或整文档读取场景,直接返回原始 Doc,无需进行子列拼接,整体开销极低。DOC Map (Sharded):针对未物化且无法整文档返回的冷字段查询,请求会被定向路由到对应的哈希分片,仅扫描相关 shard,大幅降低无效数据扫描。

图 4 说明:
- 已物化字段走列式路径(~76 ms),充分利用列存优势;
- 未物化但分片的字段走单 shard 扫描(~148 ms);
- 其余场景则回退至 Doc Map 全量扫描(~2,533 ms)。
随着时间推移,后台 Compaction 持续推进,高频访问字段会逐步被物化并进入列式路径,使系统在不牺牲写入效率的前提下,持续优化查询性能,实现读写之间的动态平衡。
4.4 JSON key 演化限制,提升系统稳定性
在 Agent Trace 或缺乏规范约束的上游数据场景中,JSON key 往往持续演化(例如从 score_* 演变为 tool_result.*),缺乏稳定边界。此时,可以适当提高 variant_doc_materialization_min_rows 阈值,使大量短生命周期或低频字段停留在 Doc Map 形态,从而实现更稳健的系统行为:
- 稳定写入路径:避免后台频繁触发大规模字段物化与字典编码,降低写放大与 Compaction 压力
- 高效整文档读取:
SELECT *可直接返回原始记录,无需子列拼装,开销更低 - 可控的冷字段访问:低频 path 仍可通过分片化 Doc Map(Sharded)定向访问,虽略低于列式性能,但有效避免列数无限膨胀带来的系统性负担
整体来看,这一策略本质上是在性能与可控性之间做边界约束:允许字段持续演进,但避免其对存储结构和系统资源造成失控影响。
4.5 适用场景
在以下三类典型业务中,Doc Mode 往往能够显著提升整体效果:
- 高稀疏日志/事件数据:字段并集规模巨大,但单条记录仅命中少量 key,且结构高度离散
- 写入压力与字段膨胀并存:由于高吞吐写入与字段快速增长,已出现明显的 Compaction 积压或写放大问题
- 混合访问模式(分析 + 回读):既需要对字段进行检索分析,又需要不定期进行整文档回读(
SELECT *)
5. Segment V3:按需加载的元数据格式
在 Doris 4.1 之前,系统采用 Segment V2 存储格式,将所有列的元数据集中存放在文件尾部(Footer)。这一设计在大规模顺序扫描场景中表现高效,但在随机读取或小范围查询时,每次都需要加载完整元数据,带来额外的 I/O 与解析开销,成为性能瓶颈。
为此,Doris 4.1 引入 Segment V3,借鉴了 Lance 以及 Vortex 等新型文件存储格式的做法,将元数据从 footer 中分离,按需加载,解决万列场景下最容易碰到的元数据膨胀、文件打开慢和随机读开销问题,在初始读取阶段的性能提升尤为显著。适用于超宽表、大量 VARIANT 子列、对象存储冷启动敏感、随机读较多的 AI 和车联网半结构化数据场景。例如 AI Observability、Prompt Debug 与在线推理分析等场景,通常只会访问少量动态 path,但需要快速完成随机查询。
开启 Segment V3 后,Doris Doc 的冷热查询性能更加均衡,避免了明显的性能分层。

以一张包含 7,000 列、10,000 个 Segment 的超宽表为例。在 Segment 打开阶段,V3 相比 V2 实现了显著提升:
- 打开速度提升最高达 16 倍
- 内存占用降低最高达 60 倍
在超宽表和高并发访问场景中,这意味着更快的响应速度与更低的资源成本。

6. 综合性能验证
为了评估各方案在宽 JSON 场景下的实际表现,我们设计了一组贴近真实业务的基准测试。测试环境与约束如下:
数据特征:
- JSON key 并集规模约 10K(无法提前定义 Schema)
- 每行随机写入 100 个 key,value 为随机数,模拟高稀疏宽表
- 总数据量 1 亿行(约 160GB),拆分为 1000 个文件,模拟高频导入场景
硬件环境:单机 16C 64GB SSD
产品及配置

访问模式:高并发写入 + 随机字段查询(避免针对特定字段优化)

6.1 存储与导入性能

存储空间:如上图可知,Doris 的 Variant Default 最佳,得益于全列式存储、无需冗余数据。

导入性能: PostgreSQL(JSONB)最高,其次为 Variant Doc,两者明显优于 ClickHouse、Elasticsearch 以及 Variant Default
6.2 查询延迟 (冷查 / 热查)

由上可知,不同系统在单项能力上各有侧重:PostgreSQL 在文档型存储与回读场景下(Q3)表现较好,但复杂分析能力受限;ClickHouse 在字段规模可控时具备优秀的列式分析能力,但在超宽 JSON 场景下容易受到路径数量、元数据和 Shared Data 机制影响。
相比之下,Doris 基于延迟物化(Doc Mode)+ 按需元数据加载(Segment V3),在宽 JSON 场景下同时兼顾写入吞吐、存储控制、复杂分析和整文档读取,在性能与资源开销之间取得了更优平衡,展现出更强的综合能力。
6.3 综合结论
综合存储、导入和查询结果可以看出,Doris Variant Doc Mode + Segment V3 的价值在于,它不是单纯选择文档存储或列式存储中的某一种,而是通过文档写入、延迟物化、按需元数据加载和列式查询执行的组合,在宽 JSON 场景下形成更适合分析型业务的折中方案,是相比传统 JSONB、搜索引擎方案以及纯列式 JSON 方案更好的一种实现路径。
7. 快速上手验证
如果你正被 JSON key 持续膨胀所困扰,可以通过以下最小可行配置快速进行验证:
CREATE TABLE IF NOT EXISTS sensor_data (
ts DATETIME NOT NULL,
device_id VARCHAR(64) NOT NULL,
model VARCHAR(128),
data VARIANT< -- Schema Template,按需设置列属性
'bat_temp' : DOUBLE,
properties(
'variant_enable_doc_mode' = 'true'
)
>,
INDEX idx_data(data) USING INVERTED PROPERTIES("field_pattern" = "status")
)
DUPLICATE KEY(`ts`, `device_id`)
DISTRIBUTED BY HASH(`device_id`) BUCKETS 16
PROPERTIES (
"replication_num" = "1",
"storage_format" = "V3"
);
注:在后续版本中,
storage_format = "V3"预计将成为宽表场景的默认选项。
查询语法同样简洁直观:
SELECT
ts,
CAST(data['bat_temp'] AS DOUBLE) AS bat_temp
FROM sensor_data
WHERE bat_temp > 60
ORDER BY ts DESC
LIMIT 100;
8. 结束语
随着 AI 应用逐渐进入 Agent 化与实时化阶段,动态字段持续增长将成为长期趋势,这也对半结构化数据系统的灵活性与扩展性提出了更高要求。通过引入 Doc Mode(延迟物化) 与 Segment V3(按需加载),Doris 在保持高写入吞吐的同时,有效缓解了元数据膨胀与查询性能退化问题,尤其在高并发、高稀疏、高演化的宽 JSON 场景中展现了明显的优势。无论是车联网、可观测性、行为分析,还是 AI 应用等领域,Doris 都能够有效应对数据字段膨胀与查询性能下降的挑战,提供了一个稳定、可扩展的解决方案。
参考资料
- Apache Doris 4.x VARIANT 使用与配置指南
- 深入理解 Doris Variant:如何让 JSON 查询性能追平列存,还能承载万列索引字段?|Deep Dive
- ClickHouse: Making complex JSON 58x faster
- Apache Iceberg Issue #5219: The metadata file is too large
- Apache Iceberg Issue #9734: Improve read times by storing schemas in external files
- Elasticsearch: Mapping Explosion
- Snowflake: Apache Iceberg V3 Variant Type
- parquet-format/VariantShredding.md at master · apache/parquet-format


