跳至主要内容
跳至主要内容
编辑此页

使用 TTL (time-to-live) 管理数据

TTL 概述

TTL (time-to-live) 指的是在经过一定时间间隔后,行或列被移动、删除或汇总的能力。虽然“time-to-live”这个表达听起来只适用于删除旧数据,但 TTL 有多种用例

  • 删除旧数据:无需多言,可以在指定的时间间隔后删除行或列
  • 在磁盘之间移动数据:在经过一定时间后,可以将数据在存储卷之间移动 - 对于部署热/温/冷架构非常有用
  • 数据汇总:在删除之前,将较旧的数据汇总成各种有用的聚合和计算
注意

TTL 可以应用于整个表或特定列。

TTL 语法

TTL 子句可以出现在列定义之后和/或表的定义末尾。使用 INTERVAL 子句定义一个时间长度(需要是 DateDateTime 数据类型)。例如,下表有两个带有 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 列从时间戳列开始的生存时间为 1 个月
  • y 列从时间戳列开始的生存时间为 1 天
  • 当间隔期满时,该列会过期。ClickHouse 会用其数据类型的默认值替换该列的值。如果数据部分中的所有列值都过期,ClickHouse 会从文件系统中的数据部分中删除该列。
注意

可以更改或删除 TTL 规则。有关更多详细信息,请参阅 表 TTL 操作 页面。

最佳实践

当使用表级 TTL 删除旧行时,我们建议您**按与 TTL 表达式中使用的相同时间字段的日期或月份对表进行分区**。

ClickHouse 可以比删除单个行更有效地删除整个分区。当您的分区键与 TTL 表达式对齐时,ClickHouse 可以在分区过期时一次性删除整个分区,而不是重写数据部分以删除过期行。

根据您的 TTL 周期选择您的分区粒度

  • 对于天/周的 TTL:使用 toYYYYMMDD(date_field) 按天分区
  • 对于月/年的 TTL:使用 toYYYYMM(date_field)toStartOfMonth(date_field) 按月分区

触发 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 表,并为这两个列添加一个 TTL,使其为 2 小时

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_hitssum_hits
  • 根据 SET 子句的定义,将 max_hitssum_hits 的默认值设置为 hits 是必要的

实现热/温/冷架构

ClickHouse Cloud 中不支持
注意

如果您使用的是 ClickHouse Cloud,则本课程中的步骤不适用。您无需担心在 ClickHouse Cloud 中移动旧数据。

在使用大量数据时,一种常见做法是随着数据的变旧而将其移动。以下是使用 TTL 命令的 TO DISKTO VOLUME 子句在 ClickHouse 中实现热/温/冷架构的步骤。(顺便说一下,它不必是热和冷的 - 您可以使用 TTL 移动数据以满足您的任何用例。)

  1. TO DISKTO 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>
  1. 上面的配置引用了三个指向 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 │
└─────────────┴────────────────┴──────────────┴──────────────┘
  1. 并且...让我们验证卷
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'] │
└─────────────┴───────────────┘
  1. 现在我们将添加一个 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';
  1. 新的 TTL 规则应该生效,但您可以强制使其以确保
ALTER TABLE my_table
    MATERIALIZE TTL
  1. 使用 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  │
└─────────────┴───────────┘
    © . This site is unofficial and not affiliated with ClickHouse, Inc.