mxkv自定义数据类型
1. 关系模型的利与弊
MatrixDB是一款关系型时序数据库,数据模型采用关系模型。
用关系模型存储时序数据有很多优点:
- 时序数据是结构化数据,很适合使用为时序优化过的关系数据库存储和处理
- 时序场景期望数据的正确性(ACID),以确保数据不错不重不丢,关系型数据库在事务方面支持更好
- 时序数据库需要强大的分析能力,关系型数据库在做复杂查询方面更有优势,如:连接、聚合、分组、窗口等
关系模型固然好用,但在做时序采集时也面临一些挑战,考虑如下场景:
- 要采集的指标过多,超过了PostgreSQL的最多1600列限制
- 不同型号设备采集指标集合差别较大,导致在回传数据时有大量列值为NULL
- 无法预知指标集,即表schema可能要经常变
2. mxkv自定义数据类型的引入
针对如上问题,MatrixDB技术团队开发了mxkv自定义数据类型,提供了kv键值存储结构,完美解决了如上场景的问题。
如下图所示,mxkv是一个键值类型,内部可以存储任意数量的键值。键数量无限制,并且可以任意增加新键。对于不确定的指标将其存在mxkv字段里即可。实际存储空间开销取决于键值数量和大小。
3. mxkv的使用
3.1 创建扩展并验证
mxkv自定义数据类型包含在MatrixTS扩展中,首先要创建扩展:
create extension matrixts;
验证mxkv是否已经开启:
mxadmin=# select '{}'::mxkv_text;
mxkv_text
-----------
{}
(1 row)
如上所示,mxkv已开启。
3.2 创建数据表并定义mxkv列
创建一张新表,并在新表中定义mxkv的整型value数据类型mxkv_int4,来存储value为整型的kv数据:
CREATE TABLE data(
time timestamp with time zone,
tag_id int,
kv mxkv_int4
)
Distributed by (tag_id);
3.3 导入键名
在使用mxkv类型前,为了压缩与查询性能优化,首先要做键名导入,来提前确定数据中包含的键名集合。
mxkv提供了UDF mxkv_import_keys
来完成键名导入。
有两种导入方式:
3.3.1 手动导入
mxkv的交互形式和json一致,手动提供json形式的kv样例,mxkv会自动提取键值并完成导入。
如下SQL会提取json中的键名'a'和'b'并导入:
mxadmin=# select mxkv_import_keys('{"a": 1, "b": 2}');
mxkv_import_keys
------------------
a
b
(2 rows)
3.3.2 基于已有表的数据导入
现有t_json表,包括json类型的字段c2:
mxadmin=# select c2 from t_json ;
c2
----------
{"k1":1}
{"k2":2}
(2 rows)
从结果可以看到,t_json表有两行数据,c2列包括k1和k2两个键。
使用mxkv_import_keys
通过表数据导入:
mxadmin=# select mxkv_import_keys('t_json'::regclass, 'c2');
mxkv_import_keys
------------------
k1
k2
(2 rows)
如上所示,在参数中提供表名和列名。相比手动导入,这种方式更方便、更快捷。前提是样例数据已存储在其他表中。
导入键名后,该键可以在当前数据库中的任何表中使用。
3.4 插入数据
键确定后,下面开始插入kv数据:
mxadmin=# insert into data values(now(), 1, '{"a":1, "b":2}');
INSERT 0 1
如上所示,插入的kv数据中,包含了刚刚导入的键'a'和'b'。
注意:kv中的键必须导入后才能正确插入,否则会出现如下错误:
mxadmin=# insert into data values(now(), 1, '{"c":1}');
psql: ERROR: unknown key "c"
LINE 1: insert into data values(now(), 1, '{"c":1}');
^
DETAIL: The key is not imported yet
HINT: Import the keys with the mxkv_import_keys() function
3.5 读取键内容
mxkv键内容的读取方式与json一样,都是使用->符号:
mxadmin=# select kv->'a' as a, kv->'b' as b from data;
a | b
---+---
1 | 2
(1 row)
注意:mxkv中->与->>效果等同。
3.6 数据类型
上面创建的表中使用了mxkv_int4类型,mxkv共支持如下几种类型:
- mxkv_int4:存储int4/int类型的32位整数值
- mxkv_float4:存储float4/real类型的32位浮点数值
- mxkv_float8:存储float8/float/double precision 类型的64位浮点数值
- mxkv_text:存储text类型的字符串值
其中mxkv_float4和mxkv_float8可以定义定点小数,如:
CREATE TABLE data(
time timestamp with time zone,
tag_id int,
kv mxkv_float4(2)
)
Distributed by (tag_id);
这样定义后,小数点两位以后的将会做四舍五入。指定小数位数后,内部存储类型将转换为整型,更有利于优化和压缩。但数值范围也会相应缩小。
- mxkv_float4(scale), scale >= 0
- mxkv_float4(0): [-2147483500, 2147483500]
- mxkv_float4(2): [-21474835.00, 21474835.00]
- mxkv_float4(4): [-214748.3500, 214748.3500]
- ......
- mxkv_float8(scale), scale >= 0
- mxkv_float8(0): [-9223372036854775000, 9223372036854775000]
- mxkv_float4(2): [-92233720368547750.00, 92233720368547750.00]
- mxkv_float8(4): [-922337203685477.5000, 922337203685477.5000]
- ......
3.7 限制
mxkv类型目前有如下限制:
- 只支持一级kv结构,不允许嵌套和数组。
- 为了保证数据有效性,导入的键值无法删除。
- 目前不支持对某个key单独更新,只能更新整个列。
4. mxkv VS json
通过前面的介绍,会发现mxkv与PostgreSQL原生支持的json类型有很多相似之处:
- 都是用json格式进行交互
- 取值都是使用->操作符 不同之处:
- mxkv只能存储一层,value下面不能再分级
- mxkv底层是二进制存储并且做了压缩和查询优化,性能要优于json类型
4.1 存储空间对比
4.2 查询时间对比
从统计结果可以看出:在500列和5000列的情况下,mxkv的存储空间和查询延时只有jsonb的40%。
5. 总结
- mxkv是一个高效的键值存储类型,方便为模式固定的关系表进行字段扩展
- mxkv支持整数、定点小数、浮点小数和字符串值类型
- mxkv存储空间占用和检索性能明显好于json