Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

TimeSeries 表引擎

Experimental 功能
ClickHouse Cloud 不支持此功能

一种用于存储时间序列的表引擎,即一组与时间戳和标签 (或标记) 关联的值:

metric_name1[tag1=value1, tag2=value2, ...] = {timestamp1: value1, timestamp2: value2, ...}
metric_name2[...] = ...

语法

CREATE TABLE name [(columns)] ENGINE=TimeSeries
[SETTINGS var1=value1, ...]
[SAMPLES db.samples_table_name | [SAMPLES INNER COLUMNS (...)] [SAMPLES INNER ENGINE engine(arguments)]]
[TAGS db.tags_table_name | [TAGS INNER COLUMNS (...)] [TAGS INNER ENGINE engine(arguments)]]
[METRICS db.metrics_table_name | [METRICS INNER COLUMNS (...)] [METRICS INNER ENGINE engine(arguments)]]

用法

一开始先使用默认设置会更简单 (可以在不指定列列表的情况下创建 TimeSeries 表) :

CREATE TABLE my_table ENGINE=TimeSeries

随后,该表可与以下协议配合使用 (必须在服务器配置中分配端口) :

外部列

TimeSeries 表的列会自动生成。这些列属于外部列,不存储任何数据,只为 SELECT/INSERT 提供接口。实际数据存储在目标表中。以下是外部列列表:

Name Type Description
metric_name String 指标名称
tags Map(String, String) 时间序列的标签映射 (标记)
time_series Array(Tuple(DateTime64(3), Float64)) (默认) 时间序列的 (timestamp, value) 对数组。该 Tuple 的 timestamp 和 scalar 元素类型可从 samples INNER COLUMNS 声明中推导得出 (参见指定外部列)
metric_family String 指标族名称 (用于指标元数据)
type String 指标类型 (例如 "counter"、"gauge")
unit String 指标单位
help String 指标说明

示例:

INSERT INTO my_table (metric_name, tags, time_series) VALUES
    ('cpu_usage', {'job': 'node_exporter', 'instance': 'host1:9100'},
     [(toDateTime64('2024-01-01 00:00:00', 3), 0.5), (toDateTime64('2024-01-01 00:01:00', 3), 0.7)])

在插入时,metric_name 可以为空,这表示指标名称是在 tags__name__ 中指定的,例如:

INSERT INTO my_table (tags, time_series) VALUES
    ({'__name__': 'cpu_usage', 'job': 'test'},
     [(toDateTime64('2024-01-01 00:00:00', 3), 0.5)])

要插入指标元数据,请写入 metric_familytypeunithelp 列:

INSERT INTO my_table (metric_name, tags, time_series, metric_family, type, unit, help) VALUES
    ('http_requests_total', {'method': 'GET'}, [(now64(), 100.0)],
     'http_requests_total', 'counter', 'requests', 'Total HTTP requests')

指定外部列

可以在 CREATE TABLE 语句中显式列出外部 time_series 列,以覆盖其默认的 Array(Tuple(DateTime64(3), Float64)) 类型。ClickHouse 会从该元组中提取时间戳类型和 scalar 类型,并将它们传递到内部samples表:

CREATE TABLE my_table (time_series Array(Tuple(UInt32, Float32))) ENGINE=TimeSeries

这相当于直接在 samples 的 INNER COLUMNS 子句中声明时间戳列和值列的类型:

CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp UInt32 CODEC(DoubleDelta, ZSTD(1)), value Float32 CODEC(ZSTD(3)))

如果在同一条 CREATE TABLE 语句中同时使用这两种形式,则声明的类型必须一致。

目标表

TimeSeries 表本身不存储数据,所有数据都保存在其目标表中。 这与 materialized view 的工作方式类似, 区别在于 materialized view 只有一个目标表, 而 TimeSeries 表有三个目标表,分别名为 samples标签metrics

这些目标表既可以在 CREATE TABLE 查询中显式指定, 也可以由 TimeSeries 表引擎自动生成内部目标表。

插入 TimeSeries 表的行会被转换、拆分为块,并写入这三个目标表。

目标表如下:

Samples 表

samples 表包含与某个标识符关联的时间序列。

samples 表必须包含以下列:

名称 必填? 默认类型 可能的类型 描述
id [x] Tuple(UInt64, UUID) any 标识一组指标名称和标签的组合
timestamp [x] DateTime64(3) DateTime64(X) 一个时间点
value [x] Float64 Float32Float64 timestamp 关联的值

引擎自行创建的列会使用时间序列压缩编解码器: timestamp CODEC(DoubleDelta, ZSTD(1))value CODEC(ZSTD(3))。近乎单调的时间戳使用通用编解码器时几乎无法 压缩,因而可能会占据 samples 表磁盘存储空间的大部分。 另请参阅调整列的类型

标签表

tags 表包含针对每种指标名称与标签组合计算出的标识符。

tags 表必须包含以下列:

名称 必填? 默认类型 可能的类型 描述
id [x] Tuple(UInt64, UUID) any (必须与 samples 表中 id 的类型匹配) id 用于标识一种指标名称与标签的组合。DEFAULT 表达式指定了如何计算该标识符
metric_name [x] LowCardinality(String) StringLowCardinality(String) 指标名称
<tag_value_column> [ ] String StringLowCardinality(String)LowCardinality(Nullable(String)) 特定标签的值;该标签的名称以及对应列的名称在 tags_to_columns 设置中指定
tags [x] Map(LowCardinality(String), String) Map(String, String)Map(LowCardinality(String), String)Map(LowCardinality(String), LowCardinality(String)) 所有标签的映射,包括表示指标名称的标签 __name__,以及 tags_to_columns 设置中枚举的标签名称。由旧版 ClickHouse 创建的表在此列中仅存储没有专用列且不含指标名称的标签;读取时会处理这两种情况
min_time [ ] Nullable(DateTime64(3)) DateTime64(X)Nullable(DateTime64(X)) 具有该 id 的时间序列的最小时间戳。如果 store_min_time_and_max_timetrue,则会创建此列
max_time [ ] Nullable(DateTime64(3)) DateTime64(X)Nullable(DateTime64(X)) 具有该 id 的时间序列的最大时间戳。如果 store_min_time_and_max_timetrue,则会创建此列

指标表

metrics 表包含有关已采集指标、其类型及描述的信息。

metrics 表必须包含以下列:

名称 必需? 默认类型 可能的类型 描述
metric_family_name [x] String StringLowCardinality(String) 指标族的名称
type [x] LowCardinality(String) StringLowCardinality(String) 指标族的类型,可为 "counter"、"gauge"、"summary"、"stateset"、"histogram"、"gaugehistogram" 之一
unit [x] LowCardinality(String) StringLowCardinality(String) 指标使用的单位
help [x] String StringLowCardinality(String) 指标的描述

创建

可以通过多种方式使用 TimeSeries 表引擎创建表。 最简单的语句

CREATE TABLE my_table ENGINE=TimeSeries

实际上会创建下列表 (可通过执行 SHOW CREATE TABLE my_table 查看) :

CREATE TABLE my_table
(
    `metric_name` String,
    `tags` Map(String, String),
    `time_series` Array(Tuple(DateTime64(3), Float64)),
    `metric_family` String,
    `type` String,
    `unit` String,
    `help` String
)
ENGINE = TimeSeries
SAMPLES INNER COLUMNS
(
    `id` Tuple(UInt64, UUID),
    `timestamp` DateTime64(3) CODEC(DoubleDelta, ZSTD(1)),
    `value` Float64 CODEC(ZSTD(3))
)
SAMPLES INNER ENGINE = MergeTree ORDER BY (id, timestamp) SETTINGS index_granularity = 32768
TAGS INNER COLUMNS
(
    `id` Tuple(UInt64, UUID) DEFAULT tuple(sipHash64(metric_name), reinterpretAsUUID(sipHash128(tags))),
    `metric_name` LowCardinality(String),
    `tags` Map(LowCardinality(String), String),
    `min_time` SimpleAggregateFunction(min, Nullable(DateTime64(3))),
    `max_time` SimpleAggregateFunction(max, Nullable(DateTime64(3)))
)
TAGS INNER ENGINE = AggregatingMergeTree PRIMARY KEY metric_name ORDER BY (metric_name, id) SETTINGS allow_dimensions_outside_sorting_key = 1, index_granularity = 8192
METRICS INNER COLUMNS
(
    `metric_family_name` String,
    `type` LowCardinality(String),
    `unit` LowCardinality(String),
    `help` String
)
METRICS INNER ENGINE = ReplacingMergeTree ORDER BY metric_family_name

因此,这些列是自动生成的,而且还有三个内部目标表,它们各自的列定义 存储在 INNER COLUMNS 子句中。

内部目标表的名称类似于 .inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.inner_id.metrics.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, 并且每个目标表都有各自的一组列:

CREATE TABLE default.`.inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, UUID),
    `timestamp` DateTime64(3) CODEC(DoubleDelta, ZSTD(1)),
    `value` Float64 CODEC(ZSTD(3))
)
ENGINE = MergeTree
ORDER BY (id, timestamp)
SETTINGS index_granularity = 32768
CREATE TABLE default.`.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `id` Tuple(UInt64, UUID) DEFAULT tuple(sipHash64(metric_name), reinterpretAsUUID(sipHash128(tags))),
    `metric_name` LowCardinality(String),
    `tags` Map(LowCardinality(String), String),
    `min_time` SimpleAggregateFunction(min, Nullable(DateTime64(3))),
    `max_time` SimpleAggregateFunction(max, Nullable(DateTime64(3)))
)
ENGINE = AggregatingMergeTree
PRIMARY KEY metric_name
ORDER BY (metric_name, id)
SETTINGS allow_dimensions_outside_sorting_key = 1, index_granularity = 8192
CREATE TABLE default.`.inner_id.metrics.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
(
    `metric_family_name` String,
    `type` LowCardinality(String),
    `unit` LowCardinality(String),
    `help` String
)
ENGINE = ReplacingMergeTree
ORDER BY metric_family_name
SETTINGS index_granularity = 8192

使用现有表创建表

语句 CREATE TABLE new_table AS existing_table 会从 existing_table 复制以下内容:

  • SETTINGS
  • 每种类型的 INNER COLUMNS
  • 每种类型的 INNER ENGINE

如果 existing_table 包含外部目标,则不允许使用该语句。 外部列列表会重新生成,而不会被复制。

调整列类型

你可以使用 INNER COLUMNS 子句来调整内部目标表中各列的类型。例如,要将时间戳以微秒存储,并将值存储为 Float32,请使用:

CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp DateTime64(6) CODEC(DoubleDelta, ZSTD(1)), value Float32 CODEC(ZSTD(3)))

未指定内部列的编解码器时,将使用默认编解码器:

CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES INNER COLUMNS (timestamp DateTime64(6), value Float32)

id

id 列包含标识符;每个标识符都是根据某个指标名称与标签的组合计算得出的。 用于生成标识符的类型和 DEFAULT 表达式可通过 TAGS INNER COLUMNS 子句自定义:

CREATE TABLE my_table ENGINE=TimeSeries
TAGS INNER COLUMNS (id UInt64 DEFAULT sipHash64(tags))

id 列可以是任何可比较的非 Nullable 类型。samples 和 标签 内部表中声明的 id 类型必须保持一致。

如果未为 id 列提供 DEFAULT 表达式且未设置 id_generator 设置,ClickHouse 会根据 id 类型自动选择 DEFAULT 表达式,但仅当 id 类型为 UUIDUInt64UInt128FixedString(16),或由其中两种类型组成的元组时才会这样做。对于此类元组,自动选择的表达式会在第一个组件中计算指标名称的哈希值,并在第二个组件中计算所有标签的哈希值。

id_generator 设置也支持相同的自定义,而无需使用 INNER COLUMNS 子句:

CREATE TABLE my_table ENGINE=TimeSeries
SETTINGS id_generator = 'sipHash64(tags)'

如果设置了此项,即使该列的 DEFAULT 包含其他表达式,也会用它来生成 id

tags

tags 列包含时间序列的所有标签,其中包括带有指标名称的 __name__ 标签。

tags_to_columns 设置允许指定将某个特定标签也存储在单独的列中, 作为 tags 列中 Map 的补充:

CREATE TABLE my_table
ENGINE = TimeSeries
SETTINGS tags_to_columns = {'instance': 'instance', 'job': 'job'}

该语句将把 instancejob 列添加到内部标签目标表中。 标签 instancejob 的值将同时存储在这些列和 tags 列中。

内部目标表的表引擎

默认情况下,内部目标表使用以下表引擎:

  • samples 表使用 MergeTree
  • 标签 表使用 AggregatingMergeTree,因为相同的数据通常会多次插入该表,因此需要一种去重方式, 同时还需要对列 min_timemax_time 进行聚合;
  • metrics 表使用 ReplacingMergeTree,因为相同的数据通常会多次插入该表,因此需要一种去重方式。

如果指定了其他表引擎,内部目标表也可以使用它们:

CREATE TABLE my_table ENGINE=TimeSeries
SAMPLES ENGINE=ReplicatedMergeTree
TAGS ENGINE=ReplicatedAggregatingMergeTree
METRICS ENGINE=ReplicatedReplacingMergeTree

标签 表将标签列 (以及 tags Map) 放在其排序键之外, 而 AggregatingMergeTree 默认会拒绝这种做法 (请参见 allow_dimensions_outside_sorting_key) 。 这在这里是安全的,因为这些列在函数上依赖于 id,而 id 是排序键的一部分,因此后台合并折叠到一起的所有 行都具有相同的值。当内部 标签 表被生成,或者其引擎像上面那样以内联方式指定时, TimeSeries 会自动为其设置 allow_dimensions_outside_sorting_key = 1; 对于手动创建的外部聚合 标签 表,则必须自行设置。

外部目标表

可以让 TimeSeries 表使用手动创建的目标表:

CREATE TABLE samples_for_my_table
(
    `id` UUID,
    `timestamp` DateTime64(3),
    `value` Float64
)
ENGINE = MergeTree
ORDER BY (id, timestamp);

CREATE TABLE tags_for_my_table ...

CREATE TABLE metrics_for_my_table ...

CREATE TABLE my_table ENGINE=TimeSeries SAMPLES samples_for_my_table TAGS tags_for_my_table METRICS metrics_for_my_table;

外部表的列类型 (idtimestampvalue,以及 tags_to_columns 中列出的各个 <tag_value_column>) 必须与 TimeSeries 表原本会在内部生成的类型一致 (类型约束请参见 Samples 表标签表指标表) 。类型不匹配会在 CREATE 时报告。

外部标签目标的 id 生成器表达式会在 INSERT 时按以下顺序解析:先是 id_generator 设置 (如果已设置) ,然后是外部表 id 列上声明的 DEFAULT (如果有) ,最后是根据 id 类型派生出的规范生成器) 。因此,该设置会覆盖外部表上声明的任何 DEFAULT——详见 The id column

修改设置

执行 CREATE 后,可更改以下两个设置:

  • id_generator
  • filter_by_min_time_and_max_time
ALTER TABLE my_table MODIFY SETTING id_generator = 'sipHash64(tags)';
ALTER TABLE my_table MODIFY SETTING filter_by_min_time_and_max_time = 0;

请注意,如果在标签表中已有数据后更改 id_generator,同一指标+tag 组合可能会生成不同的 ID——旧行会保留原来的 ID,新行则会使用新的生成器。

其他设置不能通过 ALTER ... MODIFY SETTING 更改,因为它们在 CREATE 时就已经固化在内部表的 schema 中。

设置

以下列出了在定义 TimeSeries 表时可指定的设置:

名称 类型 默认值 说明
id_generator 表达式 取决于 id 类型 根据时间序列的标签计算其标识符 (指纹) 的表达式。如果未设置,则使用 id 列的默认表达式。如果 id 列的默认表达式也未设置,则会自动选择该表达式
tags_to_columns Map 指定哪些标签应映射到 标签 表中的独立列。语法:{'tag1': 'column1', 'tag2' : column2, ...}
use_all_tags_column_to_generate_id Bool false 已废弃设置,不执行任何操作
store_min_time_and_max_time Bool true 如果设置为 true,则该表会为每个时间序列存储 min_timemax_time
aggregate_min_time_and_max_time Bool true 创建内部目标 tags 表时,此标志会启用将 min_time 列的类型设为 SimpleAggregateFunction(min, Nullable(DateTime64(3))),而不是仅使用 Nullable(DateTime64(3))max_time 列同样如此
filter_by_min_time_and_max_time Bool true 如果设置为 true,则该表会使用 min_timemax_time 列来过滤时间序列
samples_index_granularity UInt64 32768 设置内部 samples 表的 index_granularity。显式设置时,会覆盖引擎声明中的 index_granularity。对于外部 samples 表和非 MergeTree 引擎,此设置会被忽略
tags_index_granularity UInt64 8192 设置内部 标签 表的 index_granularity。显式设置时,会覆盖引擎声明中的 index_granularity。对于外部标签表和非 MergeTree 引擎,此设置会被忽略
recent_samples_ttl_seconds UInt64 345600 附加 recent samples 目标表的保留期,每个插入的样本也会写入该表。内部 recent samples 表始终会根据此设置获得 TTL toDateTime(timestamp) + toIntervalSecond(recent_samples_ttl_seconds) (覆盖引擎声明中的任何 TTL) ;外部 recent samples 表必须至少保留这么多秒的数据。时间范围落在 TTL 窗口内的查询会优先使用 recent samples 表,而非主 samples 表 (请参阅查询级别设置 time_series_prefer_recent_samples_table) 。默认值为 4 天;有效值会在 CREATE 时固定写入表定义。设置为 0 可禁用 recent samples 表
recent_samples_partition_by 表达式 toStartOfInterval(toDateTime(timestamp), toIntervalHour(5)) 内部 recent samples 表的分区键,例如 toStartOfHour(timestamp)。要求 recent_samples_ttl_seconds 非零
recent_samples_index_granularity UInt64 8192 设置内部 recent samples 表的 index_granularity。要求 recent_samples_ttl_seconds 非零

函数

以下列出了支持将 TimeSeries 表作为参数的函数:

Navigation