1.TTL
TTL即time To Live,数据的存活时间。
MergeTree中,可以为某个列字段,或者整张表设置TTL。当时间到达时,如果是列字段级别为TTL,则会删除这一列数据;如果是表级别为TTL,则会删除整张表的数据;如果同时设置了列级别和表级别的TTL,会以先到时间的为准删除数据。
无论是列或者表级别的TTL,都依靠DateTime或Date类型字段,通过对这个时间字段的INTERVAL操作,来确定TTL过期时间:
示例:
TTL time_column + interval 3 DAY
表示数据存活的时间为time_column 时间的3天之后。
TTL time_column + interval 1 MONTH
表示数据存活的时间为time_column 时间的1月之后。
INTERVAL支持的操作:second,minute,hour,day,week,month,quarter,year。
1.1 列级别的TTL
若要设置列级别的TTL,则需要在定义表字段的时候,为他们声明TTL表达式,主键字段不能被声明TTL。
示例:
CREATE TABLE t_column_ttl
(
id UInt64 COMMENT 'Primary key',
create_time Datetime,
product_desc String TTL create_time + toIntervalSecond(10),
product_type UInt8 TTL create_time + toIntervalSecond(10)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(create_time)
ORDER BY id
insert into table t_column_ttl values(1,now(),'Huawei',1),(2,now()+interval 1 minute,'Apple',2);
select * from t_column_ttl;
┌─id─┬─────────create_time─┬─product_desc─┬─product_type─┐
│ 1 │ 2021-03-11 09:12:04 │ Huawei │ 1 │
│ 2 │ 2021-03-11 09:13:04 │ Apple │ 2 │
└────┴─────────────────────┴──────────────┴──────────────┘
select sleep(10);
select * from t_column_ttl;
┌─id─┬─────────create_time─┬─product_desc─┬─product_type─┐
│ 1 │ 2021-03-11 09:12:04 │ │ 0 │
│ 2 │ 2021-03-11 09:13:04 │ Apple │ 2 │
└────┴─────────────────────┴──────────────┴──────────────┘
optimize table t_column_ttl final;
select * from t_column_ttl;
┌─id─┬─────────create_time─┬─product_desc─┬─product_type─┐
│ 1 │ 2021-03-11 09:12:04 │ │ 0 │
│ 2 │ 2021-03-11 09:13:04 │ │ 0 │
└────┴─────────────────────┴──────────────┴──────────────┘
# 执行optimize命令会强制触发TTL清理,若再次查询可以看到满足TTL条件之后,定义了TTL操作的字段列会被还原为数据类型的默认值。
# 修改列字段的TTL或者修改已有字段的TTL:
alter table t_column_ttl MODIFY COLUMN product_desc String TTL create_time + INTERVAL 2 DAY;
# 添加字段的TTL:
alter table t_column_ttl add column product_name String comment '产品名称' ttl create_time + interval 3 month;
# 查看TTL的信息:
desc t_column_ttl\G
Row 1:
──────
name: id
type: UInt64
default_type:
default_expression:
comment: Primary key
codec_expression:
ttl_expression:
Row 2:
──────
name: create_time
type: DateTime
default_type:
default_expression:
comment:
codec_expression:
ttl_expression:
Row 3:
──────
name: product_desc
type: String
default_type:
default_expression:
comment:
codec_expression:
ttl_expression: create_time + toIntervalSecond(10)
Row 4:
──────
name: product_type
type: UInt8
default_type:
default_expression:
comment:
codec_expression:
ttl_expression: create_time + toIntervalSecond(10)
1.2 表级别的TTL
可以在MergeTree的表参数中增加TTL表达式 为整张表设置TTL。
# 表的定义:
CREATE TABLE t_table_ttl
(
`id` UInt64 COMMENT '主键',
`create_time` Datetime COMMENT '创建时间',
`product_desc` String COMMENT '产品描述' ,
`product_type` UInt8 COMMENT '产品序号'
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(create_time)
ORDER BY create_time
TTL create_time + toIntervalSecond(10)
insert into table t_table_ttl values(1,now(),'Huawei',1),(2,now()+interval 1 minute,'Apple',2);
select *from t_table_ttl;
┌─id─┬─────────create_time─┬─product_desc─┬─product_type─┐
│ 1 │ 2021-03-11 09:29:30 │ Huawei │ 1 │
│ 2 │ 2021-03-11 09:30:30 │ Apple │ 2 │
└────┴─────────────────────┴──────────────┴──────────────┘
optimize table t_table_ttl final;
select *from t_table_ttl;
Ok.
0 rows in set. Elapsed: 0.009 sec.
表级别的TTL修改:
alter table t_table_ttl modify ttl create_time + interval 2 month;
alter table t_table_ttl modify ttl create_time + tointervalMonth(2);
查看信息:
SELECT
database,
name,
engine,
data_paths,
metadata_path,
metadata_modification_time,
partition_key,
sorting_key
FROM system.tables
WHERE name = 't_table_ttl'
Row 1:
──────
database: default
name: t_table_ttl
engine: MergeTree
data_paths: ['/var/lib/clickhouse/data/default/t_table_ttl/']
metadata_path: /var/lib/clickhouse/metadata/default/t_table_ttl.sql
metadata_modification_time: 2021-03-11 09:40:05
partition_key: toYYYYMM(create_time)
sorting_key: create_time
# 查看表的结构:
DESCRIBE TABLE t_table_ttl
Row 1:
──────
name: id
type: UInt64
default_type:
default_expression:
comment: 主键
codec_expression:
ttl_expression:
Row 2:
──────
name: create_time
type: DateTime
default_type:
default_expression:
comment: 创建时间
codec_expression:
ttl_expression:
Row 3:
──────
name: product_desc
type: String
default_type:
default_expression:
comment: 产品描述
codec_expression:
ttl_expression: create_time + toIntervalMinute(10)
Row 4:
──────
name: product_type
type: UInt8
default_type:
default_expression:
comment: 产品序号
codec_expression:
ttl_expression:
注意:列级别或者表级别的TTL 目前暂不支持取消操作。
1.3 TTL的运行机理
若一张MergeTree表被设置为TTL 则在写入数据时候会以数据分区为单位,在每个分区目录内生成一个ttl.txt的文件。
写入数据:
CREATE TABLE default.t_table_ttl
(
`id` UInt64 COMMENT '主键',
`create_time` DateTime COMMENT '创建时间',
`product_desc` String COMMENT '产品描述',
`product_type` UInt8 COMMENT '产品序号'
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(create_time)
ORDER BY create_time
TTL create_time + toIntervalMinute(10)
SETTINGS index_granularity = 8192;
insert into t_table_ttl(id,create_time,product_desc,product_type)values(10,now(),'Huawei',1),(20,now()+ interval 10 minute,'Apple',2);
┌─id─┬─────────create_time─┬─product_desc─┬─product_type─┐
│ 10 │ 2021-03-11 10:04:21 │ Huawei │ 1 │
│ 20 │ 2021-03-11 10:14:21 │ Apple │ 2 │
└────┴─────────────────────┴──────────────┴──────────────┘
ll /var/lib/clickhouse/data/default/t_table_ttl/
total 4
drwxr-x--- 2 clickhouse clickhouse 322 Mar 11 09:51 202103_1_1_0
drwxr-x--- 2 clickhouse clickhouse 6 Mar 11 09:51 detached
-rw-r----- 1 clickhouse clickhouse 1 Mar 11 09:51 format_version.txt
ll /var/lib/clickhouse/data/default/t_table_ttl/202103_1_1_0/
total 60
-rw-r----- 1 clickhouse clickhouse 464 Mar 11 09:51 checksums.txt
-rw-r----- 1 clickhouse clickhouse 115 Mar 11 09:51 columns.txt
-rw-r----- 1 clickhouse clickhouse 1 Mar 11 09:51 count.txt
-rw-r----- 1 clickhouse clickhouse 34 Mar 11 09:51 create_time.bin
-rw-r----- 1 clickhouse clickhouse 48 Mar 11 09:51 create_time.mrk2
-rw-r----- 1 clickhouse clickhouse 39 Mar 11 09:51 id.bin
-rw-r----- 1 clickhouse clickhouse 48 Mar 11 09:51 id.mrk2
-rw-r----- 1 clickhouse clickhouse 8 Mar 11 09:51 minmax_create_time.idx
-rw-r----- 1 clickhouse clickhouse 4 Mar 11 09:51 partition.dat
-rw-r----- 1 clickhouse clickhouse 8 Mar 11 09:51 primary.idx
-rw-r----- 1 clickhouse clickhouse 39 Mar 11 09:51 product_desc.bin
-rw-r----- 1 clickhouse clickhouse 48 Mar 11 09:51 product_desc.mrk2
-rw-r----- 1 clickhouse clickhouse 28 Mar 11 09:51 product_type.bin
-rw-r----- 1 clickhouse clickhouse 48 Mar 11 09:51 product_type.mrk2
-rw-r----- 1 clickhouse clickhouse 67 Mar 11 09:51 ttl.txt
cat /var/lib/clickhouse/data/default/t_table_ttl/202103_1_1_0/ttl.txt
ttl format version: 1
{
"table":{
"min":1615428861,"max":1615429461}}
可以看到MergeTree是通过一串JSON配置保存了TTL的相关信息。
columns 用于保存列级别的TTL信息
tables 用于保存表级别的TTL信息
min和max则保存了当前数据分区内TTL指定的日期字段的最小值和最大值分别与INTERVAL表达式计算后的时间戳。
查找JSON中格林威治时间表对应的国内时间
(ttl_max - max(create_time) expire_max
ttl_min - min(create_time) expire_min)
select toDateTime('1615428861') ttl_min,toDateTime('1615429461') ttl_max,ttl_min - min(create_time) expire_min,ttl_max - max(create_time) expire_max from t_table_ttl;
┌─────────────ttl_min─┬─────────────ttl_max─┬─expire_min─┬─expire_max─┐
│ 2021-03-11 10:14:21 │ 2021-03-11 10:24:21 │ 600 │ 600 │
└─────────────────────┴─────────────────────┴────────────┴────────────┘
可以看ttl.txt 记录的极值区间恰好等于当前数据分区内create_time的最大值和最小值加10分钟(600S ),和TTL的表达式(TTL create_time + toIntervalMinute(10))的预期相符合。
通过TTL的信息记录方式 可以推断大体的处理逻辑:
1.MergeTree 是以分区目录为单位,通过ttl.txt 记录过期时间,并以此作为判断标准。
2.每当写入一批数据时候,都会基于interval 表达式的计算结果为这个分区生成ttl.txt 文件
3.只有在MergeTree合并分区才会触发TTL过期数据的逻辑
4.在删除分区的时候,选择使用了贪婪算法,算法规则即尽可能找到会最早过期,同时时间最早的分区。
5.若一个分区内某一列因为TTL到期则全部删除,在合并之后生成的新分区目录中将不会包含这个列字段的数据文件(.bin 和.mrk)
注意:
1.TTL默认的合并频率有MergeTree的参数merge_with_ttl_timeout 控制,默认周期为86400秒。它专门维护一个专有的TTL任务队列。有别于MergeTree的常规合并任务,若这个值设置的过小则可能会带来性能损耗。
此设置意味着仅在一个分区上或发生后台合并时,每24小时执行一次TTL删除。因此,在最坏的情况下,ClickHouse现在最多每24小时删除一个与TTL delete表达式匹配的分区。
此行为可能并不理想,因此,如果您希望TTL删除表达式更快地执行删除操作,则可以修改表的merge_with_ttl_timeout设置为一个小时。
alter table t_table_ttl MODIFY SETTING merge_with_ttl_timeout = 3600;
2.除了触发TTL合并外,optimize 命令可以强制触发合并。
触发一个分区合并:optimize table t;
触发所有分区合并: optimize table t final;
3.目前没有删除ttl的声明方法,但是提供了全局控制TTL合并任务的启动和关停方法:
system stop/start TTL MERGES
更多详情,请关注微信公众号