7

我只是想知道在这样的情况下是否可以使用 ClickHouse 存储时间序列数据:带有列的模式:“some_entity_id”、“timestamp”、“metric1”、“metric2”、“metric3”、...、“metricN ”。每个包含度量名称的新列都可以动态添加到表中,同时添加具有此度量名称的条目。

在官方文档中没有找到任何关于动态表扩展的信息。

那么这个案例可以在 Clickhouse 中实现吗?

UPD: 经过一些基准测试后,我们发现 ClickHouse 写入新数据的速度比我们当前的时间序列存储快,但读取数据的速度要慢得多。

4

4 回答 4

21

将 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 有很多有用的日期和时间函数,以及高阶函数元组,我认为它几乎是一个自然的时间序列数据库。

于 2017-10-29T00:05:55.117 回答
6

将架构修改为具有 4 列可能会更好:

“some_entity_id”、“时间戳”、“metric_name”、“metric_value”

您可以在 MergeTree 索引中包含“metric_name”,以在搜索实体的特定指标时提高性能。使用和不使用它进行测试,看看它是否对您进行的查询有用。

于 2017-04-25T07:54:07.990 回答
1

你看到https://clickhouse.yandex/reference_en.html#ALTER了吗?

它仅用于 *MergeTree clickhouse 表引擎

于 2017-02-22T14:39:21.817 回答
1

编辑:

警告

在自己对几个表使用此方法后,我观察到使用 Array(Tuple(String,String,String)) 定义查询列似乎会使大型表(1+ 十亿行)上的数据库崩溃,因此请谨慎对待,我在这里描述的很可能是 UB,但我还没有从开发人员那里得到官方消息

原答案:

您可以更改表,但不能动态更改。

此外,一旦添加了一列,您总是需要向其中插入新内容,尽管您始终可以拥有一个“默认”值。

话虽如此......我发现自己需要动态插入值,并且有一个“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))

并在 touples 中存储“名称”、“类型”、“值”

这是我能想到的最接近你想要的东西。当然,您应该看一下数组操作函数,看看它们是否为您提供了您想要的东西(它们非常通用,您可以或多或少地对数组做任何事情,您可以对表格本身的一行做任何事情)。

有什么缺点?

嗯,速度。

这将使查询非常缓慢。根据您想要执行的操作,这对您来说可能是也可能不是问题。如果您过滤得足够好,并且几乎不需要对几十个或最多数亿行进行查询(并且有足够好的机器来处理查询),那么这些动态数组扩展就可以工作。

于 2017-04-28T11:46:30.953 回答