云数据库 SelectDB 版支持 ARRAY、MAP、STRUCT、JSON 和 VARIANT 等复杂数据类型,适用于存储和查询嵌套、半结构化数据。本文介绍各复杂数据类型的适用场景、建表方式及常用查询函数。
概述
在实际业务中,数据往往包含标签列表、属性键值对、嵌套对象等半结构化信息。传统的关系型列(如 VARCHAR、INT)难以高效表达这些数据。云数据库 SelectDB 版提供以下复杂数据类型:
数据类型 | 说明 | 适用场景 |
ARRAY | 有序的同类型元素集合 | 标签列表、多值属性、评分序列 |
MAP | 键值对集合,键和值分别为指定类型 | 扩展属性、配置项、动态字段 |
STRUCT | 由多个具名字段组成的结构体 | 地址信息、坐标点、嵌套实体 |
JSON | 以二进制格式存储的 JSON 数据 | Schema 不固定的半结构化数据、日志事件 |
VARIANT | 自动推断类型并按列式存储的半结构化类型 | 日志分析、用户画像等字段动态变化的场景 |
ARRAY 类型
ARRAY 类型用于存储一组相同类型的有序元素。声明语法为 ARRAY<element_type>,支持嵌套(如 ARRAY<ARRAY<INT>>)。
建表示例
CREATE TABLE user_tags (
user_id BIGINT,
tags ARRAY<VARCHAR(50)>,
scores ARRAY<INT>
)
DUPLICATE KEY(user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");写入数据
INSERT INTO user_tags VALUES
(1, ['sports', 'music', 'travel'], [90, 85, 78]),
(2, ['tech', 'gaming'], [95, 88]),
(3, ['cooking', 'reading', 'sports', 'photography'], [70, 92, 80, 65]);常用查询函数
函数 | 说明 | 示例 |
| 按下标访问元素(从 0 开始) |
|
| 返回数组元素个数 |
|
| 判断数组是否包含指定元素 |
|
| 返回排序后的数组 |
|
| 返回去重后的数组 |
|
| 将数组元素连接为字符串 |
|
更多 ARRAY 函数请参见 Apache Doris Array Functions 文档。
使用 EXPLODE 展开数组
通过 EXPLODE() 函数配合 LATERAL VIEW,可将数组中的每个元素展开为独立的行。
SELECT user_id, tag
FROM user_tags
LATERAL VIEW EXPLODE(tags) tmp AS tag;MAP 类型
MAP 类型存储键值对集合,声明语法为 MAP<key_type, value_type>。键类型必须为基本类型,值类型支持嵌套复杂类型。
建表示例
CREATE TABLE product_attrs (
product_id BIGINT,
attributes MAP<VARCHAR(50), VARCHAR(200)>
)
DUPLICATE KEY(product_id)
DISTRIBUTED BY HASH(product_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");写入数据
INSERT INTO product_attrs VALUES
(1001, {'color': 'red', 'size': 'XL', 'material': 'cotton'}),
(1002, {'color': 'blue', 'weight': '500g'}),
(1003, {'brand': 'Acme', 'origin': 'China', 'warranty': '2 years'});常用查询函数
函数 | 说明 | 示例 |
| 按键取值 |
|
| 返回键值对数量 |
|
| 返回所有键组成的数组 |
|
| 返回所有值组成的数组 |
|
| 判断是否包含指定键 |
|
更多 MAP 函数请参见 Apache Doris Map Functions 文档。
使用 EXPLODE_MAP 展开 MAP
SELECT product_id, key, value
FROM product_attrs
LATERAL VIEW EXPLODE_MAP(attributes) tmp AS key, value;STRUCT 类型
STRUCT 类型由一组具名字段组成,每个字段可以是不同的数据类型。声明语法为 STRUCT<field1:type1, field2:type2, ...>。
建表示例
CREATE TABLE orders (
order_id BIGINT,
address STRUCT<city:VARCHAR(50), street:VARCHAR(200), zipcode:VARCHAR(10)>
)
DUPLICATE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");写入数据
INSERT INTO orders VALUES
(1, NAMED_STRUCT('city', 'Beijing', 'street', 'Zhongguancun Road 1', 'zipcode', '100080')),
(2, NAMED_STRUCT('city', 'Shanghai', 'street', 'Nanjing West Road 100', 'zipcode', '200041'));查询方式
通过点号(.)访问 STRUCT 内部字段:
-- 访问 STRUCT 字段
SELECT order_id, address.city, address.zipcode FROM orders;
-- 在 WHERE 条件中使用 STRUCT 字段
SELECT * FROM orders WHERE address.city = 'Beijing';JSON 类型
JSON 类型以二进制格式存储 JSON 数据,适用于 Schema 不固定的半结构化场景。与 VARCHAR 存储 JSON 字符串相比,JSON 类型在查询时无需重复解析,性能更优。
建表示例
CREATE TABLE event_logs (
event_id BIGINT,
event_time DATETIME,
payload JSON
)
DUPLICATE KEY(event_id)
DISTRIBUTED BY HASH(event_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");写入数据
INSERT INTO event_logs VALUES
(1, '2024-01-15 10:30:00', '{"action": "login", "device": "mobile", "os": "iOS", "version": "17.2"}'),
(2, '2024-01-15 10:31:00', '{"action": "purchase", "amount": 99.9, "items": ["book", "pen"], "coupon": null}'),
(3, '2024-01-15 10:32:00', '{"action": "logout", "duration_sec": 300}');常用查询函数
函数 | 说明 | 示例 |
| 通过 JSON Path 提取值 |
|
| 提取 JSON 值并返回字符串 |
|
| 提取 JSON 值并返回整数 |
|
| 提取 JSON 值并返回浮点数 |
|
| 判断指定路径是否存在 |
|
| 返回 JSON 值的类型 |
|
更多 JSON 函数请参见 Apache Doris JSON Functions 文档。
使用建议
对于频繁查询的 JSON 字段,可考虑提取为独立列或使用 VARIANT 类型以获得更好的查询性能。
JSON 类型不支持作为 Key 列或用于分区、分桶。
JSON 类型的单个字段最大支持 1 GB。
VARIANT 类型
VARIANT 是 SelectDB 提供的半结构化数据类型,能够自动推断数据的具体类型并以列式存储。与 JSON 类型相比,VARIANT 在查询性能上更优,适合于字段可变但需要高性能分析的场景。
建表示例
CREATE TABLE user_events (
event_id BIGINT,
event_time DATETIME,
event_data VARIANT
)
DUPLICATE KEY(event_id)
DISTRIBUTED BY HASH(event_id) BUCKETS 4
PROPERTIES ("replication_allocation" = "tag.location.default: 1");写入数据
VARIANT 类型可以接收 JSON 格式的字符串,系统自动推断并以列式存储。
INSERT INTO user_events VALUES
(1, '2024-01-15 10:00:00', '{"uid": 1001, "action": "click", "page": "/home", "duration": 5.2}'),
(2, '2024-01-15 10:01:00', '{"uid": 1002, "action": "scroll", "page": "/products", "items_viewed": 12}'),
(3, '2024-01-15 10:02:00', '{"uid": 1001, "action": "purchase", "amount": 299.0, "payment": "alipay"}');查询方式
通过点号或方括号语法访问 VARIANT 字段,并可使用 CAST 进行类型转换:
-- 直接访问字段(返回 VARIANT 类型)
SELECT event_data['action'], event_data['page'] FROM user_events;
-- 使用 CAST 转换为具体类型
SELECT
CAST(event_data['uid'] AS BIGINT) AS uid,
CAST(event_data['action'] AS VARCHAR) AS action,
CAST(event_data['amount'] AS DOUBLE) AS amount
FROM user_events
WHERE CAST(event_data['action'] AS VARCHAR) = 'purchase';VARIANT 与 JSON 的选择
对比维度 | VARIANT | JSON |
存储方式 | 列式存储,自动类型推断 | 二进制 JSON 格式 |
查询性能 | 高(列式存储+向量化执行) | 中(需运行时解析) |
Schema 灵活性 | 自动适应,无需预定义 | 完全灵活 |
推荐场景 | 日志分析、用户行为等需要高性能分析的场景 | 写入频率极高且字段极不固定的场景 |
使用限制
ARRAY、MAP、STRUCT、JSON 和 VARIANT 类型不能作为表的 Key 列(如 DUPLICATE KEY、UNIQUE KEY、AGGREGATE KEY 中的列)。
复杂数据类型不能用于
DISTRIBUTED BY的分桶列。ARRAY 和 MAP 类型支持嵌套,最大嵌套深度为 9 层。
在 AGGREGATE KEY 模型的表中,复杂类型列的聚合函数只支持
REPLACE_IF_NOT_NULL和NONE。