官方文档中没有找到有关动态表扩展的任何信息。
那么,这种情况能否在Clickhouse中实现?
更新:经过一些基准测试,我们发现ClickHouse比我们当前的时间序列存储更快地写入新数据,但读取数据要慢得多。
使用CH作为时间序列数据库有多种方法。 我个人偏好的是使用一个字符串数组来存储指标名称,一个Float64数组来存储指标值。
这是一个示例时间序列表:
CREATE TABLE ts1(
entity String,
ts UInt64, -- timestamp, milliseconds from January 1 1970
m Array(String), -- names of the metrics
v Array(Float32), -- values of the metrics
d Date MATERIALIZED toDate(round(ts/1000)), -- auto generate date from ts column
dt DateTime MATERIALIZED toDateTime(round(ts/1000)) -- auto generate date time from ts column
) ENGINE = MergeTree(d, entity, 8192)
这里我们正在为一个实体 (cpu) 加载两个指标 (负载、温度):
INSERT INTO ts1(entity, ts, m, v)
VALUES ('cpu', 1509232010254, ['load','temp'], [0.85, 68])
查询CPU负载:
SELECT
entity,
dt,
ts,
v[indexOf(m, 'load')] AS load
FROM ts1
WHERE entity = 'cpu'
┌─entity─┬──────────────────dt─┬────────────ts─┬─load─┐
│ cpu │ 2017-10-28 23:06:50 │ 1509232010254 │ 0.85 │
└────────┴─────────────────────┴───────────────┴──────┘
以元组数组的形式获取数据:
SELECT
entity,
dt,
ts,
arrayMap((mm, vv) -> (mm, vv), m, v) AS metrics
FROM ts1
┌─entity─┬──────────────────dt─┬────────────ts─┬─metrics─────────────────────┐
│ cpu │ 2017-10-28 23:06:50 │ 1509232010254 │ [('load',0.85),('temp',68)] │
└────────┴─────────────────────┴───────────────┴─────────────────────────────┘
将数据作为元组的行获取:
SELECT
entity,
dt,
ts,
arrayJoin(arrayMap((mm, vv) -> (mm, vv), m, v)) AS metric
FROM ts1
┌─entity─┬──────────────────dt─┬────────────ts─┬─metric────────┐
│ cpu │ 2017-10-28 23:06:50 │ 1509232010254 │ ('load',0.85) │
│ cpu │ 2017-10-28 23:06:50 │ 1509232010254 │ ('temp',68) │
└────────┴─────────────────────┴───────────────┴───────────────┘
获取所需指标的行:
SELECT
entity,
dt,
ts,
arrayJoin(arrayMap((mm, vv) -> (mm, vv), m, v)) AS metrics
FROM ts1
WHERE metrics.1 = 'load'
┌─entity─┬──────────────────dt─┬────────────ts─┬─metrics───────┐
│ cpu │ 2017-10-28 23:06:50 │ 1509232010254 │ ('load',0.85) │
└────────┴─────────────────────┴───────────────┴───────────────┘
将指标名称和值作为列获取:
SELECT
entity,
dt,
ts,
arrayJoin(arrayMap((mm, vv) -> (mm, vv), m, v)) AS metric,
metric.1 AS metric_name,
metric.2 AS metric_value
FROM ts1
┌─entity─┬──────────────────dt─┬────────────ts─┬─metric────────┬─metric_name─┬─metric_value─┐
│ cpu │ 2017-10-28 23:06:50 │ 1509232010254 │ ('load',0.85) │ load │ 0.85 │
│ cpu │ 2017-10-28 23:06:50 │ 1509232010254 │ ('temp',68) │ temp │ 68 │
└────────┴─────────────────────┴───────────────┴───────────────┴─────────────┴──────────────┘
由于ClickHouse拥有许多有用的日期和时间函数,以及高阶函数和元组,我认为它几乎是一个天然的时间序列数据库。
修改您的模式以具有4列可能更好:
"some_entity_id","timestamp","metric_name","metric_value"
您可以在MergeTree索引中包含"metric_name",以在搜索实体的特定度量时提高性能。测试一下是否有用,看看您进行的查询类型。
你看过https://clickhouse.yandex/reference_en.html#ALTER吗?
它仅用于*MergeTree ClickHouse表引擎。
编辑:
警告
在我自己使用这种方法来处理几个表格后,我发现使用Array(Tuple(String,String,String))定义查询列会导致大型表格(10亿行以上)崩溃,因此需要谨慎对待。我在这里描述的可能是未定义行为,但我还没有从开发人员那里得到官方消息。
原始答案:
您可以更改表格,但不能动态更改。
此外,一旦添加了列,您总是需要将新内容插入其中,尽管您可以始终有一个“默认”值。
话虽如此... 我发现自己需要动态插入值,有一个“Hack”可以做到,即使用这个列:
Array(Tuple(String,String))
因此,对于一行,您的数组可能是:
[("metric_1":"val1"), ("metric_2":"val2")]
[("metric_1":"val3"), ("metric_3":"val4"), ("metric_4":"val5")]
array(Tuple(String,String,String))
在元组存储中,有"name"、"type"和"value"。
这是我能想到的最接近你想要的东西。当然,你应该查看数组操作函数,看看它们是否提供了你想要的功能(它们非常通用,你几乎可以像处理表格本身的行一样处理数组)。
缺点是什么?
速度慢。
这将使查询非常缓慢。根据你想要做什么,这可能是或不是你的问题。如果你足够好地过滤数据,并且很少需要对数十亿行甚至最多数百万行进行查询(并且有足够好的机器来处理查询),那么这些动态数组扩展可能会起作用。