导语
ClickHouse原生支持数据生命周期(TTL)管理的功能。
可以为整个表或每个单独的列设置TTL子句。表级TTL也可以指定在磁盘和分区之间自动移动数据的逻辑。 表达式的计算结果必须为Date
或DateTime
数据类型。
示例:
代码语言:txt复制TTL time_column
TTL time_column interval
要定义间隔,可使用时间间隔运算符INTERVAL
TTL date_time INTERVAL 1 MONTH
TTL date_time INTERVAL 15 HOUR
TTL列
当列中的值过期时,ClickHouse会将其替换为列数据类型的默认值。如果数据块中的所有列值均已过期,则ClickHouse将从文件系统中的数据块中删除此列。
TTL子句不能用于主键列。
示例:
创建一个TTL表
代码语言:txt复制CREATE TABLE example_table
(
d DateTime,
a Int TTL d INTERVAL 1 MONTH,
b Int TTL d INTERVAL 1 MONTH,
c String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d;
将TTL添加到现有表的列中
代码语言:txt复制ALTER TABLE example_table
MODIFY COLUMN
c String TTL d INTERVAL 1 DAY;
更改列的TTL
代码语言:txt复制ALTER TABLE example_table
MODIFY COLUMN
c String TTL d INTERVAL 1 MONTH;
TTL表
Table可以具有一个用于删除过期行的表达式,并可以具有多个用于在磁盘或分区之间自动移动数据块的表达式。当表格中的行到期时,ClickHouse会删除所有对应的行。对于数据块移动功能,数据块中的所有行都必须满足移动表达式条件。
TTL expr [DELETE|TO DISK 'aaa'|TO VOLUME 'bbb'], ...
TTL动作在TTL时间表达式之后给出,它决定在TTL表达式满足后(到达了当前的时间)将要执行的操作:
DELETE
- 删除过期行 (默认动作);
TO DISK 'aaa'
- 移动数据至磁盘A;
TO VOLUME 'bbb'
- 移动数据至磁盘B.
示例:
创建一个TTL表
代码语言:txt复制CREATE TABLE example_table
(
d DateTime,
a Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(d)
ORDER BY d
TTL d INTERVAL 1 MONTH [DELETE],
d INTERVAL 1 WEEK TO VOLUME 'aaa',
d INTERVAL 2 WEEK TO DISK 'bbb';
修改表的TTL表达式
代码语言:txt复制ALTER TABLE example_table
MODIFY TTL d INTERVAL 1 DAY;
删除数据
当ClickHouse合并数据块时,将删除TTL过期的数据。
对于已过期的数据,ClickHouse将执行“计划外(off-schedule)”的合并。可以通过设置merge_with_ttl_timeout
控制这种合并的频率。如果该值设定的太低,可能会执行许多计划外的合并,消耗大量资源。
如果在两个合并间隔之间执行SELECT
查询,则可能会获取到过期的数据。为了避免这种情况,请在SELECT之前使用OPTIMIZE
查询主动触发合并。
使用案例
某用户反馈TTL表不生效,设定的过期时间已经达到了,通过SELECT
还是能查到过期的数据,通过上文可以看出用户可能是在两个合并间隔之间执行的查询,这样就可能会获取到过期的数据。为了进一步确认过期数据是否被清除以及计划外的合并有没有执行,可通过查询日志来进行诊断。
grep "expired TTL" /data/clickhouse/clickhouse-server/logs/clickhouse-server.log
上诉命令可以在ClickHouse日志文件中查到过期数据被处理的情况,如果有相关的日志信息则说明ClickHouse已经进行了off-schedule
合并,再查询时就不会获取到过期的数据了。
测试分析
如果日志文件中查不到到ClickHouse对过期数据的处理日志就需要进一步测试该项功能是否work了,对此可在集群中创建一个TTL表进行测试。
代码语言:txt复制CREATE TABLE ttl_table_test
(
Ds DateTime,
Id Int
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(Ds)
ORDER BY Ds
TTL Ds INTERVAL 10 MINUTE;
ALTER TABLE ttl_table_test MODIFY SETTING merge_with_ttl_timeout = 60;
INSERT INTO TABLE ttl_table_test VALUES(now()-interval 9 minute,1),(now()-interval 8 minute,2),(now()-interval 7 minute,3);
SELECT * FROM ttl_table_test;
上诉sql指令首先创建了一个TTL表ttl_table_test
并设置了超时时间为10分钟,后续修改了计划外合并的周期为60秒(默认为86400秒,一天),之后向表中插入了3条数据,这3条数据分别会在1分钟后、2分钟后、3分钟后过期。最后查询表中的数据。
INSERT INTO TABLE ttl_table_test VALUES(now()-interval 10 minute,1),(now()-interval 9 minute,2),(now()-interval 8 minute,3);
如果往TTL表里插入已过时数据,则已过时数据不会被存储下来。
merge_with_ttl_timeout
时间窗口内未进行后台或强制OPTIMIZE
合并表,已经过期的数据就会还在,所以会查询到过期的数据。
使用
代码语言:txt复制ALTER TABLE ttl_table_test MODIFY SETTING merge_with_ttl_timeout = 60;
将merge_with_ttl_timeout
设定为60秒,可以很快验证过期数据是否被删除(P.S. 设定过低会频繁执行合并,耗费系统资源。)或者先进行OPTIMIZE
再查询
OPTIMIZE TABLE ttl_table_test final;
可以看到过期数据已经不存在了。
参考文献
- clickhouse.tech