暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MergeTree系列表引擎之TTL​

ClickHouse周边 2021-03-11
1166

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信息
          minmax则保存了当前数据分区内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:212021-03-11 10:24:21600600
          └─────────────────────┴─────────────────────┴────────────┴────────────┘

                  可以看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



                文章转载自ClickHouse周边,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论