Skip to main content
一种用于存储时间序列的表引擎,即一组与时间戳和标签 (或标记) 关联的值:
这是一个私有预览功能,未来的发行版中可能会发生不向后兼容的变更。 使用 enable_time_series_table 设置 启用 TimeSeries 表引擎。 输入命令 set enable_time_series_table = 1。
TimeSeries 表引擎在 ClickHouse Cloud 中作为私有预览功能提供。 已参与私有预览的服务已配置 enable_time_series_table 设置。其他 ClickHouse Cloud 服务 没有此配置,且您无法自行在此类服务上启用该引擎。

语法

关键字 SAMPLES 有一个别名 DATA,关键字 METRIC FAMILIES 有一个别名 METRICS,保留它们都是为了保持向后兼容性。 版本低于 4 的表定义使用 METRICS 写入,以便较旧的 server 能够读取它。

用法

一开始先使用默认设置会更简单 (可以在不指定列列表的情况下创建 TimeSeries 表) :
随后,该表可与以下协议配合使用 (必须在服务器配置中分配端口) :

外部列

TimeSeries 表的列会自动生成。这些列属于外部列,不存储任何数据,只为 SELECT/INSERT 提供接口。实际数据存储在目标端表中。以下是外部列列表: 示例:
在插入时,metric_name 可以为空,这表示指标名称是在 tags 的 __name__ 中指定的,例如:
要插入指标元数据,请写入 metric_family、type、unit 和 help 列:

指定外部列

可以在 CREATE TABLE 语句中显式列出外部 samples 列,以覆盖其默认的 Array(Tuple(DateTime64(3), Float64)) 类型 (其旧名称 time_series 同样可用) 。ClickHouse 会从该元组中提取时间戳类型和 scalar 类型,并将它们传递到内部samples表:
这相当于直接在 samples 的 INNER COLUMNS 子句中声明时间戳列和值列的类型:
如果在同一条 CREATE TABLE 语句中同时使用这两种形式,则声明的类型必须一致。

目标端表

TimeSeries 表本身不存储数据,所有数据都保存在其目标端表中。 这与 materialized view 的工作方式类似, 区别在于 materialized view 只有一个目标端表, 而 TimeSeries 表有三个必需的目标端表,分别名为 samples、标签 和 指标族, 以及一个默认启用的可选 最近样本 目标端表 (请参阅 recent_samples_ttl_seconds 设置) 。 这些目标端表既可以在 CREATE TABLE 查询中显式指定, 也可以由 TimeSeries 表引擎自动生成内部目标端表。 插入 TimeSeries 表的行会被转换、拆分为块,并写入这些目标端表。 目标端表如下:

样本表

样本 表包含与某个标识符关联的时间序列。 样本 表必须包含以下列: 引擎自行创建的列会使用时间序列压缩编解码器: timestamp CODEC(Delta, T64, ZSTD(3)) 和 value CODEC(ALP, ZSTD(3))。近乎单调的时间戳使用通用编解码器时几乎无法 压缩,因而可能会占据样本表磁盘存储空间的大部分。 引擎会为其内部样本表和最近样本表启用 ALP,无需设置 enable_alp_codec。 另请参阅调整列的类型。

最近样本表

_最近样本_表是可选的,默认启用 (请参阅 recent_samples_ttl_seconds 设置;将其设为零可禁用该表) 。该表包含 TTL 未超过该设置所定义时长的样本副本,并且必须与样本表具有相同的列。 生成的 timestamp 列使用 CODEC(Delta, T64, ZSTD(3)), 生成的 value 列使用 CODEC(ALP, ZSTD(3))。 每个插入的样本都会同时写入样本表和最近样本表。 时间范围落在 TTL 窗口内的查询会从最近样本表而非主样本表读取数据, 因为前者小得多 (可通过查询级别设置 time_series_prefer_recent_samples_table 禁用此行为) 。 内部最近样本表的 TTL 始终由 recent_samples_ttl_seconds 设置决定。

标签表

tags 表包含针对每种指标名称与标签组合计算出的标识符。 tags 表必须包含以下列: 版本 5 及更高版本中,使用 MergeTree 家族引擎新建的内部 tags 表会在 tags 上建立倒排文本索引: INDEX tags_idx tags TYPE text(tokenizer = 'keyValuePairs')。它通过同时查找键和值来加速 PromQL 中诸如 {job="api"} 这样的精确标记匹配。与空字符串的比较也会匹配缺失的标记,并且不会使用该索引。 在 TAGS INNER COLUMNS 中显式声明的索引会替换默认索引。已有的表以及外部 tags 表会保留其原有索引;可在其 tags target table 上添加并 materialize 该索引以启用它。

指标族表

指标族 表包含有关正在采集的指标族、这些指标族的类型及其描述的信息。 指标族是一组名称相同 (__name__ 标签) 且类型相同的指标,例如,直方图就是一个由多个指标组成的指标族。 指标族 表必须包含以下列:

创建

可以通过多种方式创建使用 TimeSeries 表引擎的表。 最简单的语句是
实际上会创建如下表 (可执行 SHOW CREATE TABLE my_table 查看) :
因此,列会自动生成。此外,还有四个内部目标表,各自的列定义存储在 INNER COLUMNS 子句中。 recent_samples_ttl_seconds 设置以其默认值写入 SETTINGS 子句:该设置定义最近样本表的 TTL,因此其有效值在创建时便已固定。 此外,最新的 schema 版本已固定写入 version 设置中 (参见 Schema 版本控制) 。 内部目标表的名称类似于 .inner_id.samples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx、 .inner_id.recentsamples.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx、.inner_id.tags.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx、 .inner_id.metricfamilies.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, 并且每个目标表都有各自的一组列:

基于现有表创建表

语句 CREATE TABLE new_table AS existing_table 会创建一个配置与 existing_table 相同的 TimeSeries 表, 其中 existing_table 必须是 TimeSeries 表。existing_table 的外部目标不会被复制:该语句必须自行声明 这些目标。 该语句会从 existing_table 复制:
  • SETTINGS 子句,但不包括 version:新表始终使用最新版本。语句中 指定的设置会按名称与复制的设置合并,因此语句中指定的设置优先于复制的设置,而 name = DEFAULT 会将复制的设置重置为默认值;
  • 每个内部表的 INNER COLUMNS 和 INNER ENGINE 子句。会保留自定义列 (例如额外列、带有 codec 或 DEFAULT 表达式的列) 和自定义引擎部分 (例如带参数的引擎、自定义排序键 或引擎设置) ;其他列和引擎部分会根据新表的设置进行调整,因此 例如语句中指定的 tags_to_columns、aggregate_min_time_and_max_time 或 tags_index_granularity 会生效。
除非语句自行声明,否则 id、时间戳和值列的类型,以及内部引擎的复制类型 (MergeTree、 ReplicatedMergeTree 或 SharedMergeTree) 也会从 existing_table 继承。 外部列列表会重新生成,不会被复制。 由较早版本的 ClickHouse 创建的表可以用作 existing_table:新表会采用当前的 结构,例如当前的 id 类型和默认标识符表达式。

调整列类型

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

id 列

id 列包含标识符;每个标识符都是根据某个指标名称与标签的组合计算得出的。 用于生成标识符的类型和 DEFAULT 表达式可通过 TAGS INNER COLUMNS 子句自定义:
id 列可以是任何可比较的非 Nullable 类型。samples 和 标签 内部表中声明的 id 类型必须保持一致。 如果未为 id 列提供 DEFAULT 表达式且未设置 id_generator 设置,ClickHouse 会根据 id 类型自动选择 DEFAULT 表达式,但仅当 id 类型为 UUID、UInt64、UInt128、FixedString(16)、这些类型包裹在 LowCardinality 中的形式,或由其中两种类型组成的元组时才会这样做。对于此类元组,自动选择的表达式会在第一个组件中计算指标名称的哈希值,并在第二个组件中计算所有标签的哈希值。 使用 LowCardinality 标识符类型 (例如 Tuple(UInt64, LowCardinality(UUID))) 可使标识符保持字典编码:samples 表会按块存储小型字典并配合 dictionary indexes,而不是在每一行中重复完整的标识符,从而减少查询读取的数据量。 id_generator 设置也支持相同的自定义,而无需使用 INNER COLUMNS 子句:
如果设置了此项,即使该列的 DEFAULT 包含其他表达式,也会用它来生成 id。 id 列的类型也可以通过 id_type 设置指定,而无需使用 INNER COLUMNS 子句:
设置了 id_generator 时,id_type 设置会在 CREATE 时自动记录, 因此该定义会保留此表达式所针对的类型。

tags 列

tags 列包含时间序列的所有标签,其中包括带有指标名称的 __name__ 标签。 tags_to_columns 设置允许指定将某个特定标签也存储在单独的列中, 作为 tags 列中 Map 的补充:
该语句将把 instance 和 job 列添加到内部标签目标表中。 标签 instance 和 job 的值将同时存储在这些列和 tags 列中。
在由旧版 ClickHouse 创建的表中,tags 列仅包含未存储在专用 列中且不含指标名称的标签,而 all_tags 列是一个临时列,会在插入时填充 除指标名称外的所有标签。

内部目标端表的表引擎

默认情况下,内部目标端表使用以下表引擎: 生成的内部表的引擎家族遵循 default_table_engine 查询级别设置: 当 default_table_engine = ReplicatedMergeTree 或 SharedMergeTree 时,内部表使用相应的 Replicated 或 Shared 引擎。当 default_table_engine = None (或任何其他值) 时,内部表的引擎 必须显式指定。 所有内部表必须具有相同的复制类型:如果其中一个表采用复制 (或共享) 机制,其他内部 表也必须采用复制 (或共享) 机制,否则其内容会在副本之间出现差异。例如, 声明 SAMPLES INNER ENGINE = ReplicatedMergeTree(...) 要求其他内部引擎也使用复制引擎 - 要么显式声明,要么通过 default_table_engine = ReplicatedMergeTree 生成。 如果指定了其他表引擎,内部目标端表也可以使用它们:
标签 表将标签列 (以及 tags Map) 放在其排序键之外, 而 AggregatingMergeTree 默认会拒绝这种做法 (请参见 allow_dimensions_outside_sorting_key) 。 这在这里是安全的,因为这些列在函数上依赖于 id,而 id 是排序键的一部分,因此后台合并折叠到一起的所有 行都具有相同的值。当内部 标签 表被生成,或者其引擎像上面那样以内联方式指定时, TimeSeries 会自动为其设置 allow_dimensions_outside_sorting_key = 1; 对于手动创建的外部聚合 标签 表,则必须自行设置。

外部目标端表

可以让 TimeSeries 表使用手动创建的目标表:
外部表也可用作最近样本目标 (RECENT SAMPLES my_recent_samples_table 子句) 。 此类表必须与外部样本表具有相同的列,并且必须至少保留 recent_samples_ttl_seconds 秒的数据,这由用户负责。 外部表的列类型 (id、timestamp、value,以及 tags_to_columns 中列出的各个 <tag_value_column>) 必须与 TimeSeries 表原本会在内部生成的类型一致 (类型约束请参见 Samples 表、标签表 和 指标族表) 。类型不匹配会在 CREATE 时报告。 外部标签表的 id 列类型以及生成标识符的表达式会在 CREATE 时记录到 id_type 和 id_generator 设置中 (从 version 2 开始) ,因此 TimeSeries 表的定义会保留它们:例如,CREATE TABLE ... AS my_table 会从 my_table 的定义中读取 id 类型,而无需读取其外部目标端表。如果未指定 id_generator 设置,则会将其设置为外部表 id 列上声明的 DEFAULT (如果有) ,否则设置为根据 id 类型派生出的规范生成器。即使外部表的 DEFAULT 之后发生变化,也仍会使用已记录的表达式来生成 id——详见 id 列。

修改设置

执行 CREATE 后,可更改以下两个设置:
  • id_generator
  • filter_by_min_time_and_max_time
请注意,如果在标签表中已有数据后更改 id_generator,同一指标+标签组合可能会生成不同的 ID——旧行会保留原来的 ID,新行则会使用新的生成器。 其他设置不能通过 ALTER ... MODIFY SETTING 更改:其中大多数在 CREATE 时就已经固化在内部表的 schema 中, 而 version 设置会在 CREATE 时自动固定,并用于标识 schema 本身 (参见 Schema 版本控制) 。

设置

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

Schema 版本控制

TimeSeries 表引擎与 PromQL 执行层仍处于活跃开发阶段: 目标端表的集合及其结构可能在不同 ClickHouse 版本之间发生变化。 为了让此类变化可被检测,每个 TimeSeries 表都会将自身版本记录在 version 设置中。 建表时,该版本会自动固化到 CREATE 查询中——其取值为服务器已知的最新版本 (当前为 5) —— 并持久化在表的元数据中,且无法通过 ALTER 修改。在该设置引入之前创建的表被视为版本 0。 通常在 CREATE TABLE 查询中省略该设置即可——此时表会自动采用最新版本。 如果服务器支持所指定的版本,也可以显式指定 version;此时该表会按照该版本的方式来定义 (请参阅版本历史) 。 CREATE TABLE ... AS other_table 不会复制另一个表的版本,请参阅基于现有表创建表。 服务器支持一个版本范围,且不同场景所要求的最低版本可能不同:使用 SELECT 读取、使用 INSERT 或 Prometheus 远程写入协议写入、以及执行 PromQL (prometheusQuery、 prometheusQueryRange 和 timeSeriesSelector 表函数、 promql dialect 以及 Prometheus HTTP 查询 API) ,三者的最低版本要求各不相同:
  • 如果 TimeSeries 表的版本对 PromQL 而言过旧,则针对该表的 PromQL 查询会被拒绝。异常信息会建议重建该表: 创建一个新的 TimeSeries 表,通过 INSERT ... SELECT 查询复制数据,再用新表替换旧表。
  • 如果版本过旧而无法写入,则 INSERT 查询和 Prometheus 远程写入协议会被拒绝,但 SELECT 查询仍可正常工作。
  • 如果版本对服务器而言完全过旧,则针对该表的所有查询 (SHOW CREATE TABLE、DETACH 和 DROP 除外) 都会被拒绝。

版本历史

函数

以下列出了支持将 TimeSeries 表作为参数的函数:
最后修改于 2026年9月26日