---
keywords: [压缩策略, 时间窗口压缩, 严格窗口压缩, SST 文件, 手动压缩]
description: 介绍 GreptimeDB 中的压缩策略，包括时间窗口压缩策略（TWCS）和严格窗口压缩策略（SWCS），以及它们的概念、参数和使用示例。
---

# Compaction

对于基于 LSM 树的数据库，压缩是极其关键的。它将重叠的碎片化 SST 文件合并成一个有序的文件，丢弃已删除的数据，同时显著提高查询性能。

从 v0.9.1 版本开始，GreptimeDB 提供了控制 SST 文件如何压缩的策略：时间窗口压缩策略（TWCS）和严格窗口压缩策略（SWCS）。

## 概念

让我们从 GreptimeDB 中压缩的核心概念开始介绍。

### SST 文件

当内存表刷新到持久存储（如磁盘和对象存储）时，会生成排序的 SST 文件。

在 GreptimeDB 中，SST 文件中的数据行按[tag 列](/user-guide/concepts/data-model.md)和时间戳组织，如下所示。每个 SST 文件覆盖特定的时间范围。当查询指定一个时间范围时，GreptimeDB 只检索可能包含该范围内数据的相关 SST 文件，而不是加载所有已持久化的文件。

![SST layout](/compaction-sst-file-layout.jpg)

通常，在实时写入工作负载中，SST 文件的时间范围不会重叠。然而，由于数据删除和乱序写入等因素，SST 文件可能会有重叠的时间范围，这会影响查询性能。

### 时间窗口

时间序列工作负载呈现出显著的“窗口”特征，即最近插入的行更有可能被读取。因此，GreptimeDB 将时间轴逻辑上划分为不同的时间窗口，我们更关注压缩那些落在同一时间窗口内的 SST 文件。

特定表的时间窗口参数通常是从最新 flush 到存储的 SST 文件推断出来的，或者如果选择了 TWCS，您可以在建表时手动指定时间窗口。

GreptimeDB 预设了一组窗口大小，它们是：
- 1 小时
- 2 小时
- 12 小时
- 1 天
- 1 周
- 1 年
- 10 年

如果未指定时间窗口大小，GreptimeDB 将在第一次压缩时推断窗口，通过从上述集合中选择**能够覆盖所有要压缩文件的整个时间跨度的**，**最小的**时间窗口作为时间窗口大小。

例如，在第一次压缩期间，所有输入 SST 文件的时间跨度为 4 小时，那么 GreptimeDB 将选择 12 小时作为该表的时间窗口，并将此参数持久化以便后续的压缩中使用。

GreptimeDB 将包含最近插入时间戳的窗口视为**活跃窗口（active window）**，而将之前的那些窗口视为**非活跃窗口（inactive window）**。

### 有序组
有序组（sorted runs）是一个包含已排序且时间范围不重叠的 SST 文件的集合。

例如，一个表包含 5 个 SST，时间范围如下（全部包括在内）：`[0, 10]`, `[12, 23]`, `[22, 25]`,`[24, 30]`,`[26,33]`，我们可以找到 2 个有序组：

![num-of-sorted-runs](/compaction-num-sorted-runs.jpg)


有序组的数量往往能够反映 SST 文件的有序性。更多的有序组通常会导致查询性能变差，因为特定时间范围的查询往往会命中多个重叠的文件。压缩的主要目标是减少有序组的数量。

### 层级

基于 LSM 树的数据库常常有多个层级，数据的键（key）会逐层进行合并。GreptimeDB 只有两个层级，分别是 0（未压缩）和 1（已压缩）。

## 压缩策略

GreptimeDB 提供了上述两种压缩策略，但在创建表时只能选择时间窗口压缩策略（TWCS）。严格窗口（SWCS）仅在执行手动压缩时可用。

## 时间窗口压缩策略（TWCS）

TWCS 主要旨在减少压缩过程中的读 / 写放大。

它将要压缩的文件分配到不同的时间窗口。对于每个窗口，TWCS 会识别有序组。如有序组的数量超过了允许的最大值，TWCS 会找到一个解决方案，在考虑合并惩罚的同时将其减少到阈值以下。如果有序组的数量没有超过阈值，TWCS 会检查是否存在过多的文件碎片，并在必要时合并这些碎片文件，因为 SST 文件数量也会影响查询性能。

对于窗口分配，SST 文件可能跨越多个时间窗口。为了确保不受陈旧数据影响，TWCS 根据 SST 的最大时间戳来进行分配。在时间序列工作负载中，无序写入很少发生，即使发生了，最近数据的查询性能也比陈旧数据更为重要。

TWCS 提供了 5 个参数供调整：
- `max_active_window_runs`: 活跃窗口中最大允许存在的有序组数量（默认为 4）
- `max_active_window_files`: 活跃窗口中最大允许存在的文件数量（默认为 4）
- `max_inactive_window_runs`: 非活跃窗口中最大允许存在的有序组数量（默认为 1）
- `max_inactive_window_files`: 非活跃窗口中最大允许存在的文件数量（默认为 1）
- `max_output_file_size`: compaction 产生文件的最大大小（默认无限制）

您可以为活跃窗口和非活跃窗口设置不同的阈值。这很重要，因为乱序写入通常发生在活跃窗口中。通过允许更多重叠文件存在于活跃窗口，TWCS 在数据摄取过程中减少了写放大，并在活跃窗口变为非活跃时合并所有这些文件。

以下图表显示了当最大活跃窗口允许的有序组数量为 1 时，活跃窗口中的文件如何被压缩：
- 在 A 中，有两个 SST 文件`[0, 3]`和`[5, 6, 9]`，但由于这两个文件的时间范围不重叠，因此只有一个有序组。
- 在 B 中，一个新的 SST 文件`[1, 4]`被刷新，因此形成了两个有序组。然后将 `[0, 3]` 和 `[1, 4]` 合并为 `[0, 1, 3, 4]`.
- 在 C 中，一个新的 SST 文件 ` [9, 10 ] ` 被刷新，并且它将与 `[5, 6, 10 ] ` 合并以创建 `[5, 6, 9, 10]`.
- D 是最终状态，两个压缩后的文件中形成一个有序组。

![compaction-twcs-active.jpg](/compaction-twcs-active.jpg)

### 指定 TWCS 参数
用户可以在创建表时指定前述的 TWCS 参数，例如：

```sql
CREATE TABLE monitor (
  host STRING,
  ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP() TIME INDEX,
  cpu FLOAT64 DEFAULT 0,
  memory FLOAT64,
  PRIMARY KEY(host))
WITH (
    'compaction.type'='twcs', 
    'compaction.twcs.max_active_window_runs'='4', 
    'compaction.twcs.max_active_window_files'='8', 
    'compaction.twcs.max_inactive_window_runs'='1',
    'compaction.twcs.max_inactive_window_files'='2',
    'compaction.twcs.max_output_file_size'='500MB'
    );
```

## 严格窗口压缩策略（SWCS）和手动压缩

与 TWCS 根据 SST 文件的最大时间戳为每个窗口分配一个 SST 文件不同的是，严格窗口策略（SWCS）将 SST 文件分配给**所有与此文件的时间范围重叠**的窗口，正如其名称所示。因此，一个 SST 文件可能会包含在多个压缩输出中。由于其在压缩期间的高读取放大率，SWCS 并不是默认的压缩策略。然而，当用户需要手动触发压缩以重新组织 SST 文件布局时，它是有用的，特别是当单个 SST 文件跨越较大的时间范围而显著减慢查询速度时。GreptimeDB 提供了一个简单的 SQL 函数来触发手动压缩：

```sql
ADMIN COMPACT_TABLE(
    <table_name>, 
    <strategy_name>, 
    [<strategy_parameters>]
);
```

`<strategy_name>` 参数可以是 `twcs` 或 `swcs`（大小写不敏感），分别指定时间窗口压缩策略和严格窗口压缩策略。
对于 `swcs` 策略， `<strategy_parameters>` 指定用于拆分 SST 文件的窗口大小（以秒为单位）。例如：

```sql
ADMIN COMPACT_TABLE(
    "monitor", 
    "swcs", 
    "3600"
);

+--------------------------------------------------------------------+
| ADMIN compact_table(Utf8("monitor"),Utf8("swcs"),Utf8("3600")) |
+--------------------------------------------------------------------+
|                                                                  0 |
+--------------------------------------------------------------------+
1 row in set (0.01 sec)
```

执行此语句时，GreptimeDB 会将每个 SST 文件按 1 小时（3600 秒）的时间跨度拆分成多个分块，并将这些分块合并为一个输出文件，确保没有重叠的文件。

下图展示了一次 SWCS 压缩的过程：

在图 A 中，有 3 个重叠的 SST 文件，分别是 `[0, 3]`（也就是包含 0、1、2、3 的时间戳）、`[3, 8]` 和 `[8, 10]`。
严格窗口压缩策略会将覆盖了窗口 0、4、8 的文件 `[3, 8]` 分别分配给 3 个窗口，从而分别和 `[0, 3]` 以及 `[8, 10]` 合并。
图 B 给出了最终的压缩结果，分别有 3 个文件： `[0, 3]`、`[4, 7]` 和 `[8, 10]`，它们彼此互相不重叠。

![compaction-strict-window.jpg](/compaction-strict-window.jpg)
