clickhouse作为时间序列存储

ua4mk5z4  于 2021-07-15  发布在  ClickHouse
关注(0)|答案(4)|浏览(913)

我只是想知道在这种情况下,clickhouse是否可以用于存储时间序列数据:带有列的模式:“some \ entity \ id”,“timestamp”,“metric1”,“metric2”,“metric3”,“metricn”。其中,每个包含度量名称的新列都可以动态添加到表中,同时添加具有此度量名称的条目。
在官方文件中没有发现任何关于动态表扩展的信息。
那么这个案例能在clickhouse中实现吗?
upd:经过一些基准测试,我们发现clickhouse写入新数据的速度比我们当前的时间序列存储快,但读取数据的速度要慢得多。

vohkndzv

vohkndzv1#

最好将架构修改为有4列:
“某些\u实体\u id”,“时间戳”,“度量\u名称”,“度量\u值”
您可以在mergetree索引中包含“metric\u name”,以提高搜索实体的特定度量时的性能。使用和不使用它进行测试,看看它对您所做的查询是否有用。

izj3ouym

izj3ouym2#

使用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 │
└────────┴─────────────────────┴───────────────┴───────────────┴─────────────┴──────────────┘

由于ch有很多有用的日期和时间函数,以及高阶函数和元组,我认为它几乎是一个自然的时间序列数据库。

wyyhbhjk

wyyhbhjk3#

你看到了吗https://clickhouse.yandex/reference_en.html#alter ?
它仅用于*mergetree clickhouse表引擎

f5emj3cl

f5emj3cl4#

编辑:
警告
在我自己对几个表使用了这个方法之后,我观察到用数组(tuple(string,string,string))定义查询列似乎会使大型表(10多亿行)上的数据库崩溃,所以对此有点怀疑,我在这里描述的可能是ub,但我还没有从devs那里得到正式的消息
原始答案:
可以更改表,但不能动态更改。
另外,一旦一个列被添加,你总是需要在其中插入新的内容,尽管你总是可以有一个“默认”值。
话说回来。。。我发现自己需要动态地插入值,为此有一个“hack”,即使用以下列:

Array(Tuple(String,String))

这基本上意味着您可以拥有一个包含任意多个值的数组,并在其中插入“description”“value”的元素。
因此,对于一行,数组可以是:

[("metric_1":"val1"), ("metric_2":"val2")]

对于另一个:

[("metric_1":"val3"), ("metric_3":"val4"), ("metric_4":"val5")]

这里的想法是,您可以将值从string转换为任何其他类型,因此本质上您可以在其中存储您想要的任何类型。
如果您需要知道每个运算符的类型,并且类型可以不同怎么办?。。。好:

array(Tuple(String,String,String))

在touples商店“name”,“type”,“value”
这是我能想到的最符合你要求的东西。当然,您应该看看数组操作函数,看看它们是否提供了您想要的功能(它们非常通用,您可以或多或少地使用数组来处理表本身的行)。
缺点是什么?
好吧,速度。
这将使查询速度非常慢。取决于你想做什么,这对你来说可能是个问题,也可能不是。如果您能够很好地过滤数据,并且几乎不需要对几十行或最多数亿行进行查询(并且有足够好的机器来处理查询),那么这些动态数组扩展就无法工作了。

相关问题