使用 TTL (生存时间) 管理数据
TTL 概述
TTL(生存时间)是指在经过一定时间间隔后移动、删除或汇总行或列的功能。虽然“生存时间”这个词听起来只适用于删除旧数据,但 TTL 有多种用例
- 删除旧数据:毫无疑问,您可以在指定的时间间隔后删除行或列
- 在磁盘之间移动数据:经过一段时间后,您可以在存储卷之间移动数据——这对于部署热/温/冷架构非常有用
- 数据汇总:在删除旧数据之前,将其汇总成各种有用的聚合和计算结果
TTL 可以应用于整个表或特定列。
TTL 语法
TTL
子句可以出现在列定义之后和/或表定义的末尾。使用 INTERVAL
子句定义时间长度(需要为 Date
或 DateTime
数据类型)。例如,下表有两个带有 TTL
子句的列
CREATE TABLE example1 (
timestamp DateTime,
x UInt32 TTL timestamp + INTERVAL 1 MONTH,
y String TTL timestamp + INTERVAL 1 DAY,
z String
)
ENGINE = MergeTree
ORDER BY tuple()
- x 列的生存时间是从 timestamp 列开始的 1 个月
- y 列的生存时间是从 timestamp 列开始的 1 天
- 当时间间隔过去后,列就会过期。ClickHouse 会将列值替换为其数据类型的默认值。如果数据部分中的所有列值都过期,ClickHouse 会从文件系统中的数据部分删除此列。
TTL 规则可以更改或删除。有关更多详细信息,请参阅表 TTL 操作页面。
触发 TTL 事件
过期行的删除或聚合不是立即发生的——它只在表合并期间发生。如果您有一个未积极合并的表(无论出于何种原因),则有两个设置可以触发 TTL 事件
merge_with_ttl_timeout
:重复执行带有删除 TTL 的合并之前的最短延迟时间(秒)。默认值为 14400 秒(4 小时)。merge_with_recompression_ttl_timeout
:重复执行带有重新压缩 TTL(在删除之前汇总数据的规则)的合并之前的最短延迟时间(秒)。默认值:14400 秒(4 小时)。
因此,默认情况下,您的 TTL 规则至少每 4 小时应用一次到您的表。如果您需要更频繁地应用 TTL 规则,只需修改上述设置即可。
这不是一个很好的解决方案(或者我们建议您经常使用的解决方案),但您也可以使用 OPTIMIZE
强制合并
OPTIMIZE TABLE example1 FINAL
OPTIMIZE
会初始化表部分的非计划合并,而 FINAL
会在您的表已经是单个部分时强制重新优化。
删除行
要在经过一定时间后从表中删除整个行,请在表级别定义 TTL 规则
CREATE TABLE customers (
timestamp DateTime,
name String,
balance Int32,
address String
)
ENGINE = MergeTree
ORDER BY timestamp
TTL timestamp + INTERVAL 12 HOUR
此外,还可以根据记录的值定义 TTL 规则。这可以通过指定 where 条件轻松实现。允许多个条件
CREATE TABLE events
(
`event` String,
`time` DateTime,
`value` UInt64
)
ENGINE = MergeTree
ORDER BY (event, time)
TTL time + INTERVAL 1 MONTH DELETE WHERE event != 'error',
time + INTERVAL 6 MONTH DELETE WHERE event = 'error'
删除列
假设您只想让 balance 和 address 列过期,而不是删除整行。让我们修改 customers
表,并为这两个列添加 2 小时的 TTL
ALTER TABLE customers
MODIFY COLUMN balance Int32 TTL timestamp + INTERVAL 2 HOUR,
MODIFY COLUMN address String TTL timestamp + INTERVAL 2 HOUR
实现汇总
假设我们希望在一定时间后删除行,但保留一些数据以用于报告目的。我们不需要所有详细信息——只需要一些历史数据的聚合结果即可。这可以通过在 TTL
表达式中添加 GROUP BY
子句以及表中的一些列来存储聚合结果来实现。
假设在下表 hits
中,我们希望删除旧行,但在删除行之前保留 hits
列的总和和最大值。我们需要一个字段来存储这些值,并且需要在 TTL
子句中添加一个 GROUP BY
子句来汇总总和和最大值
CREATE TABLE hits (
timestamp DateTime,
id String,
hits Int32,
max_hits Int32 DEFAULT hits,
sum_hits Int64 DEFAULT hits
)
ENGINE = MergeTree
PRIMARY KEY (id, toStartOfDay(timestamp), timestamp)
TTL timestamp + INTERVAL 1 DAY
GROUP BY id, toStartOfDay(timestamp)
SET
max_hits = max(max_hits),
sum_hits = sum(sum_hits);
关于 hits
表的一些说明
TTL
子句中的GROUP BY
列必须是PRIMARY KEY
的前缀,并且我们希望按日期开始对结果进行分组。因此,toStartOfDay(timestamp)
已添加到主键中- 我们添加了两个字段来存储聚合结果:
max_hits
和sum_hits
- 根据
SET
子句的定义方式,将max_hits
和sum_hits
的默认值设置为hits
是必要的
实现热/温/冷架构
如果您使用的是 ClickHouse Cloud,则本课程中的步骤不适用。您无需担心在 ClickHouse Cloud 中移动旧数据。
处理大量数据时,常见的做法是随着数据变得越来越旧而将其移动。以下是使用 TTL
命令的 TO DISK
和 TO VOLUME
子句在 ClickHouse 中实现热/温/冷架构的步骤。(顺便说一下,它不一定是热和冷——您可以使用 TTL 移动数据以满足您的任何用例。)
TO DISK
和TO VOLUME
选项指的是在 ClickHouse 配置文件中定义的磁盘或卷的名称。创建一个名为my_system.xml
(或任何文件名)的新文件以定义您的磁盘,然后定义使用您的磁盘的卷。将 XML 文件放在/etc/clickhouse-server/config.d/
中以使配置应用于您的系统
<clickhouse>
<storage_configuration>
<disks>
<default>
</default>
<hot_disk>
<path>./hot/</path>
</hot_disk>
<warm_disk>
<path>./warm/</path>
</warm_disk>
<cold_disk>
<path>./cold/</path>
</cold_disk>
</disks>
<policies>
<default>
<volumes>
<default>
<disk>default</disk>
</default>
<hot_volume>
<disk>hot_disk</disk>
</hot_volume>
<warm_volume>
<disk>warm_disk</disk>
</warm_volume>
<cold_volume>
<disk>cold_disk</disk>
</cold_volume>
</volumes>
</default>
</policies>
</storage_configuration>
</clickhouse>
- 上述配置引用了三个指向 ClickHouse 可以读取和写入的文件夹的磁盘。卷可以包含一个或多个磁盘——我们为这三个磁盘中的每一个定义了一个卷。让我们查看磁盘
SELECT name, path, free_space, total_space
FROM system.disks
┌─name────────┬─path───────────┬───free_space─┬──total_space─┐
│ cold_disk │ ./data/cold/ │ 179143311360 │ 494384795648 │
│ default │ ./ │ 179143311360 │ 494384795648 │
│ hot_disk │ ./data/hot/ │ 179143311360 │ 494384795648 │
│ warm_disk │ ./data/warm/ │ 179143311360 │ 494384795648 │
└─────────────┴────────────────┴──────────────┴──────────────┘
- 并且……让我们验证卷
SELECT
volume_name,
disks
FROM system.storage_policies
┌─volume_name─┬─disks─────────┐
│ default │ ['default'] │
│ hot_volume │ ['hot_disk'] │
│ warm_volume │ ['warm_disk'] │
│ cold_volume │ ['cold_disk'] │
└─────────────┴───────────────┘
- 现在,我们将添加一个
TTL
规则,该规则将在热、温、冷卷之间移动数据
ALTER TABLE my_table
MODIFY TTL
trade_date TO VOLUME 'hot_volume',
trade_date + INTERVAL 2 YEAR TO VOLUME 'warm_volume',
trade_date + INTERVAL 4 YEAR TO VOLUME 'cold_volume';
- 新的
TTL
规则应该会实现,但您可以强制执行以确保
ALTER TABLE my_table
MATERIALIZE TTL
- 使用
system.parts
表验证您的数据是否已移动到预期的磁盘
Using the system.parts table, view which disks the parts are on for the crypto_prices table:
SELECT
name,
disk_name
FROM system.parts
WHERE (table = 'my_table') AND (active = 1)
响应将如下所示
┌─name────────┬─disk_name─┐
│ all_1_3_1_5 │ warm_disk │
│ all_2_2_0 │ hot_disk │
└─────────────┴───────────┘
相关内容
- 博客和网络研讨会:使用 TTL 管理 ClickHouse 中的数据生命周期