📅 2025年3月20日
📦 ck
版本 25.1.3.23
🏡 MergeTree之TTL和存储策略
1️⃣ MergeTree
之前分为几个阶段了解过 MergeTree
了,这里主要讲TTL和存储策略
🌟 TTL
在
MergeTree
中可以设置、表、列的 TTL
,如果同时设置了则会以哪个先到期为先,但是无论是列级别还是表级别的 TTL
,都需要依托某个 DateTime
或 Date
类型的字段,通过对这个时间字段的 INTERVAL
操作,来表述 TTL
的过期时间,比如如下:
-- 表示在这两个类型字段时间内的 3 天后过期
TTL [DateTime|Date类型字段] + INTERVAL 3 DAY
INTERVAL完整的操作包括 SECOND
、MINUTE
、HOUR
、DAY
、WEEK
、MONTH
、QUARTER
和 YEAR
🌊 列级别TTL
如果想要设置列级别的
TTL
,则需要在定义表字段的时候,为它们声明 TTL
表达式,主键字段不能被声明 TTL
如下语句中code和type会在create_time 时间基础上+10秒后被删除
CREATE TABLE ttl_table_v1(
id String,
create_time DateTime,
code String TTL create_time + INTERVAL 10 SECOND,
type UInt8 TTL create_time + INTERVAL 10 SECOND
) ENGINE = MergeTree PARTITION BY toYYYYMM(create_time) ORDER BY id
然后测试一下,在插入数据10秒后再次查看次表会发现数据会被归为零值
-- 插入数据
INSERT INTO TABLE ttl_table_v1 VALUES('A000',now(),'C1',1), ('A000',now() + INTERVAL 10 MINUTE,'C1',1);
-- 查看数据
SELECT *
FROM ttl_table_v1
Query id: 991b269b-5513-4a94-876f-e2983fadf68d
┌─id───┬─────────create_time─┬─code─┬─type─┐
1. │ A000 │ 2025-03-20 22:58:59 │ C1 │ 1 │
2. │ A000 │ 2025-03-20 23:08:59 │ C1 │ 1 │
└──────┴─────────────────────┴──────┴──────┘
-- 数10秒后使用optimize触发合并
optimize TABLE ttl_table_v1 FINAL
-- 再次查看
SELECT *
FROM ttl_table_v1
Query id: a785b458-a0a6-4da0-be7c-342ff9970361
┌─id───┬─────────create_time─┬─code─┬─type─┐
1. │ A000 │ 2025-03-20 22:58:59 │ │ 0 │
2. │ A000 │ 2025-03-20 23:08:59 │ C1 │ 1 │
└──────┴─────────────────────┴──────┴──────┘
如果想要修改列字段的TTL,或是为已有字段添加TTL,则可以使用ALTER语句
ALTER TABLE ttl_table_v1 MODIFY COLUMN code String TTL create_time + INTERVAL 1 DAY
目前ck没有删除列表级别ttl方法
🌊 表级别TTL
表级别和列级别差不多,这里就只举列子如何定义和修改语句
CREATE TABLE ttl_table_v2(
id String,
create_time DateTime,
code String TTL create_time + INTERVAL 1 MINUTE,
type UInt8
)
ENGINE = MergeTree PARTITION BY toYYYYMM(create_time) ORDER BY create_time
TTL create_time + INTERVAL 1 DAY
-- 修改
ALTER TABLE ttl_table_v2 MODIFY TTL create_time + INTERVAL 3 DAY
🖌 原理
如果一张
MergeTree
表被设置了 TTL
表达式,那么在写入数据时,会以数据分区为单位,在每个分区目录内生成一个名为 ttl.txt
的文件如下
/var/lib/clickhouse/data/default/ttl_table_v1/202503_1_1_3# ls
checksums.txt data.bin metadata_version.txt primary.cidx
columns.txt data.cmrk3 minmax_create_time.idx serialization.json
count.txt default_compression_codec.txt partition.dat ttl.txt
##查看ttl文件
root@DESKTOP-HLBQNO4:/var/lib/clickhouse/data/default/ttl_table_v1/202503_1_1_3# cat ttl.txt
ttl format version: 1
{"columns":[{"name":"code","min":1742483349,"max":1742483349,"finished":0},{"name":"type","min":1742483349,"max":1742483349,"finished":0}]}
root@DESKTOP-HLBQNO4:/var/lib/clickhouse/data/default/ttl_table_v1/202503_1_1_3#
MergeTree
是通过一串 JSON
配置保存了TTL的相关信息,其中:
- columns用于保存列级别TTL信息;
- table用于保存表级别TTL信息;
- min和max则保存了当前数据分区内,TTL指定日期字段的最小值、最大值分别与INTERVAL表达式计算后的时间戳
TTL
的大致处理逻辑
MergeTree
以分区目录为单位,通过ttl.txt
文件记录过期时间,并将其作为后续的判断依据- 每当写入一批数据时,都会基于
INTERVAL
表达式的计算结果为这个分区生成ttl.txt
文件 - 只有在
MergeTree
合并分区时,才会触发删除TTL过期数据的逻辑 - 在选择删除的分区时,会使用贪婪算法,它的算法规则是尽可能找到会最早过期的,同时年纪又是最老的分区(合并次数更 多,
MaxBlockNum
更大的) - 如果一个分区内某一列数据因为TTL到期全部被删除了,那么在合并之后生成的新分区目录中,将不会包含这个列字段的数据文件(.bin和.mrk)
(1)TTL默认的合并频率由
MergeTree
的merge_with_ttl_timeout
参数控制,默认86400秒,即1天。它维 护的是一个专有的TTL任务队列。有别于MergeTree的常规合并任务,如果这个值被设置的过小,可能会带来性能损耗。(2)除了被动触发TTL合并外,也可以使用optimize命令强制触发合并。例如,触发一个分区合并
(3)最新版本加入了取消TTL了: https://clickhouse.com/docs/sql-reference/statements/alter/ttl#remove-ttl