[Preview] Flat JSON
本文介绍 Flat JSON 的基本概念,以及如何使用该功能。
自 2.2.0 版本起,StarRocks 支持 JSON 数据类型,用于支持更加灵活的数据存储。但在查询 JSON 时,大部分场景并不是直接读取完整的 JSON 数据,而是访问指定路径下的数据,举例:
-- 将日志中必填的字段存储为固定字段,将其他经常随业务变更的字段打包为 JSON 存储。
SELECT
time,
event,
user,
get_json_string(remain_json, "$.from_system"),
get_json_string(remain_json, "$.tag")
FROM logs;
由于 JSON 类型的特殊性,在查询中 JSON 类型的性能表现并不如标准类型(INT,STRING 等),其原因有:
- JSON 类型是半结构化类型,在存储上需要存储每行数据的结构信息,存储占用多,压缩效率低。
- 在查询时,需要根据运行时数据来检测数据结构,难以实现向量化执行优化。
- 在查询时,需要读取完整的 JSON 数据,其中包含了大量冗余字段。
StarRocks 从 3.3.0 版本起,支持 Flat JSON 功能,旨在优化 JSON 数据的查询性能,降低用户使用 JSON 的成本。
什么是 Flat JSON
Flat JSON 的核心原理是在导入时检测 JSON 数据,将 JSON 数据中的公共字段提取为标准类型数据存储。在查询 JSON 时,通过这些公共字段数据优化 JSON 的查询速度。示例数据:
1, {"a": 1, "b": 21, "c": 3, "d": 4}
2, {"a": 2, "b": 22, "d": 4}
3, {"a": 3, "b": 23, "d": [1, 2, 3, 4]}
4, {"a": 4, "b": 24, "d": null}
5, {"a": 5, "b": 25, "d": null}
6, {"c": 6, "d": 1}
在导入上述这组 JSON 数据时,a
和 b
两个字段在大部分的 JSON 数据中都存在并且其数据类型相似(都是 INT),那么可以将 a
,b
两个字段的数据都从 JSON 中读取出来,单独存储为两列 INT。当查询中使用到这两列时,就可以直接读取 a
,b
两列的数据,无需读取 JSON 中额外的字段,在计算时减少对 JSON 结构的处理开销。
使用说明
- StarRocks 存算一体集群自 v3.3.0 起支持 Flat JSON,存算分离集群自 v3.3.3 起支持。
- StarRocks 所有表类型都支持 Flat JSON。
- 兼容历史数据,无须重新导入。历史数据会和 Flat JSON 打平的数据共存。
- 向历史表导入新数据时,自动通过 Compaction 完成 Flat JSON 操作。
在 v3.3.0、v3.3.1、v3.3.2 版本中:
- 导入数据时,支持提取公共字段、单独存储为 JSON 类型,未实现类型推导。
- 会同时存储提取的列和原始 JSON 数据。提取的数据会在原始数据删除时一起删除。
自 v3.3.3 版本起:
- Flat JSON 提取的结果分为公共的列和保留字段列,当所有 JSON Schema 一致时,不会生成保留字段列。
- Flat JSON 仅存储公共字段列和保留字段列,不会再额外存储原始 JSON 数据。
- 导入数据时,公共字段会自动推导类型为 BIGINT/LARGEINT/DOUBLE/STRING,不能识别的类型推导为 JSON 类型,保留字段列会存储为 JSON 类型。
使用 Flat JSON
使用 Flat JSON 需要先在 BE 上开启动态参数 enable_json_flat
(默认 false
)。开启后新导入的 JSON 数据会自动打平。
curl -XPOST http://<be_host>:<be_http_port>/api/update_config?enable_json_flat=true
在查询数据时,开启 Session 变量 cbo_prune_json_subfield
(默认 false
)。开启后支持对 JSON 子列进行裁剪。
SET cbo_prune_json_subfield = true;
验证 Flat JSON 是否生效
-
导入数据后,可以查询对应列提取的子列:
SELECT flat_json_meta(<json_column>)
FROM <table_name>[_META_]; -
查询中,可以通过 Query Profile 观察几个相关指标:
PushdownAccessPaths
:下推存储的子字段路径数量。AccessPathHits
:命中 Flat JSON 子字段的次数,其子项详细打印了具体命中的 JSON。AccessPathUnhits
:未命中 Flat JSON 子字段的次数,其子项详细打印了具体未命中的 JSON 。JsonFlattern
:当存在未命中 Flat JSON 时,系统现场提取子列的耗时。