这是一个私有预览功能,未来的发行版中可能会发生不向后兼容的变更。
使用
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表:
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 列是一个临时列,会在插入时填充
除指标名称外的所有标签。内部目标端表的表引擎
默认情况下,内部目标端表使用以下表引擎:- samples 表使用 MergeTree;
- 最近样本 表使用 MergeTree,按 5 小时分桶进行分区 (请参见 recent_samples_partition_by 设置),其
TTL源自 recent_samples_ttl_seconds 设置,并启用ttl_only_drop_parts,因此会整体删除过期的 parts; - 标签 表使用 AggregatingMergeTree,因为相同的数据通常会多次插入该表,因此需要一种去重方式,
同时还需要对列
min_time和max_time进行聚合; - 指标族 表使用 ReplacingMergeTree,因为相同的数据通常会多次插入该表,因此需要一种去重方式。
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_generatorfilter_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 表作为参数的函数: