分类 :3.存储引擎 | 篇章:06 Compaction

适用版本:TDengine v3.x(v3.3.x / v3.4.x) | 最后更新:2026-05-31
Compaction(合并/压实)是后台将多个小文件或无序文件整理为有序大文件的过程。它是写入性能与查询性能之间的平衡器------写入时允许数据以 STT 形式快速落盘,后台再异步整理成查询友好的有序结构。
核心概念速查表
| 概念 | 说明 |
|---|---|
| STT Compaction | STT 文件数达到阈值时触发的合并 |
| STT_TRIGGER | 触发合并的 STT 文件数量阈值 |
| File Merge | 将 STT 数据与主数据文件(.data)合并 |
| 写放大 | 一份数据在合并过程中被多次重写 |
| 后台线程 | Compaction 在专用后台线程执行,不阻塞读写 |
| COMPACT 命令 | 用户手动触发全库合并 |
详细解析
1. 为什么需要 Compaction
没有 Compaction 的问题:
高频写入 → MemTable 频繁刷盘 → STT 文件持续累积
查询时:
FileSet 0: .data(有序) + stt1 + stt2 + stt3 + stt4 + ...
查询需要打开所有文件 + 多路归并排序
STT 越多 → 查询越慢 → 性能持续退化
Compaction 解决:
定期将 STT 合并到主文件 → 维持查询性能稳定
2. Compaction 触发条件
| 触发方式 | 条件 | 说明 |
|---|---|---|
| 自动触发 | STT 文件数 ≥ STT_TRIGGER | Commit 后检查 |
| 手动触发 | COMPACT DATABASE |
用户主动执行 |
| 定时触发 | COMPACT_INTERVAL(企业版) | 按配置的时间间隔自动执行 |
3. STT Compaction 流程
STT Compaction 流程:
触发:FileSet X 的 STT 文件数 ≥ STT_TRIGGER
│
▼
① 选择参与合并的文件:
- 所有 STT 文件
- 主文件 .head + .data + .sma(如果需要)
│
▼
② 多路归并排序:
- 为每个 STT 文件和主文件各创建一个读取器
- 按 (uid, timestamp) 排序键合并
- 同一 uid 同一时间戳 → 取版本号最高的行
│
▼
③ 输出到新文件:
- 按子表分块(每块 MAXROWS 行)
- 编码压缩每个数据块
- 写入新的 .head + .data + .sma
│
▼
④ 文件替换:
- 新文件 fsync
- 更新 current(原子切换)
- 删除旧的 STT 文件和旧主文件
│
▼
⑤ 完成
4. Compaction 策略
STT_TRIGGER 对 Compaction 行为的控制:
STT_TRIGGER = 1:
→ 每次 Commit 直接与主文件合并
→ 永远只有 .head + .data + .sma,无 STT
→ 写放大最高,但查询最快
STT_TRIGGER = 2(默认):
→ Commit 写入 STT 文件
→ 2 个 STT 时触发合并
→ 均衡策略
STT_TRIGGER = 4~8:
→ 允许 4~8 个 STT 共存
→ 合并频率降低
→ 写放大低,但查询时多路合并开销增加
STT_TRIGGER = 16:
→ 大量 STT 容忍
→ 适合"写多读少"的归档场景
→ 查询时需要合并 16 个文件(较慢)
5. 合并中的数据处理
合并过程中的特殊处理:
① 版本冲突(同 uid + 同时间戳):
旧文件: ts=T1, ver=100, value=10.0
STT: ts=T1, ver=200, value=10.5
→ 保留 ver=200 的数据(最新版本胜出)
② 删除标记(.tomb):
.tomb: uid=1001, delete [T1, T5]
.data: uid=1001, 有 T1~T10 的数据
→ 合并后:T1~T5 的行被物理删除
→ .tomb 中对应记录也被清理
③ Schema 版本不同:
旧数据块 schema_version=1(3列)
当前 schema_version=3(5列)
→ 合并时按新 Schema 输出
→ 旧数据中不存在的新列填 NULL
→ 已删除的旧列不输出
6. 后台调度机制
Compaction 后台线程调度:
┌────────────────────────────────────────────┐
│ Compaction 调度器 │
│ │
│ 全局队列: │
│ [VNode2-FileSet3] [VNode5-FileSet1] ... │
│ │
│ 工作线程数:可配置(默认跟随 CPU 核数) │
│ │
│ 优先级: │
│ 1. STT 文件最多的 FileSet 优先 │
│ 2. 手动 COMPACT 命令优先 │
│ │
│ 资源限制: │
│ - I/O 带宽限制(避免影响前台读写) │
│ - 内存限制(合并缓冲区有上限) │
└────────────────────────────────────────────┘
7. 手动 COMPACT
sql
-- 对整个数据库触发 Compaction
COMPACT DATABASE power;
-- 指定时间范围的 Compaction(企业版)
COMPACT DATABASE power START WITH '2024-01-01' END WITH '2024-06-30';
手动 COMPACT 的用途:
- 大量 DELETE 后回收空间
- Schema 变更后清理旧格式数据
- 维护窗口内集中整理,减少日常开销
8. 写放大分析
写放大计算:
假设 STT_TRIGGER = 4:
数据生命周期中被写入磁盘的次数:
1. MemTable flush → 写入 STT (第 1 次写盘)
2. 4 个 STT 合并 → 写入主文件(第 2 次写盘)
写放大 = 2(可接受)
如果 STT_TRIGGER = 1:
1. MemTable flush → 直接合并写入主文件
但合并时需要读取旧主文件 + 写入新主文件
写放大 = 2~3(旧数据被重写)
对比:
STT_TRIGGER 大 → 写放大低(仅合并一次)
STT_TRIGGER 小 → 写放大高(频繁重写)
代码示例
配置 Compaction 策略
sql
-- 写密集型(高吞吐,容忍查询稍慢)
CREATE DATABASE write_heavy STT_TRIGGER 8;
-- 读密集型(查询快,容忍写入开销)
CREATE DATABASE read_heavy STT_TRIGGER 1;
-- 均衡(推荐默认)
CREATE DATABASE balanced STT_TRIGGER 2;
-- 动态调整
ALTER DATABASE power STT_TRIGGER 4;
企业版自动 Compaction
sql
-- 每 24 小时自动 Compact 一次
ALTER DATABASE power COMPACT_INTERVAL 24h;
-- 只 Compact 7 天前的数据(避免影响热数据)
ALTER DATABASE power COMPACT_TIME_RANGE -365d, -7d;
-- 在凌晨 2 点开始 Compact
ALTER DATABASE power COMPACT_TIME_OFFSET 2;
性能考量
Compaction 对系统的影响
| 影响 | 说明 | 缓解措施 |
|---|---|---|
| 磁盘 I/O 增加 | 合并需要读旧文件+写新文件 | I/O 限速 |
| CPU 占用 | 解压旧数据+压缩新数据 | 后台低优先级 |
| 临时磁盘占用 | 新旧文件短暂共存 | 预留 20% 磁盘余量 |
| 查询延迟抖动 | 合并期间 I/O 竞争 | 避开业务高峰 |
监控 Compaction 状态
bash
# 观察 taosd 日志
grep -i "compact\|merge" /var/log/taos/taosdlog.0
# 关注:
# "start to merge, fid:X, sttFiles:N"
# "merge finished, elapsed:XXXms"
FAQ
Q1: Compaction 期间查询会受影响吗?
会有轻微影响。Compaction 占用磁盘 I/O 带宽,可能导致查询的磁盘读取变慢。但不会阻塞查询------查询读旧文件,Compaction 写新文件,逻辑上互不冲突。
Q2: STT_TRIGGER 设多少合适?
- 子表少(< 1000)+ 每表高频写入 → STT_TRIGGER = 1~2
- 海量子表(> 10万)+ 每表低频写入 → STT_TRIGGER = 4~8
- 纯归档(几乎不查询)→ STT_TRIGGER = 8~16
Q3: COMPACT DATABASE 会阻塞写入吗?
不会。COMPACT 在后台执行,前台读写正常进行。但期间磁盘 I/O 压力增大,可能间接影响写入延迟。
Q4: Compaction 可以取消吗?
当前不支持中途取消。一旦开始合并某个 FileSet,会运行到完成。如果需要控制 Compaction 的影响,建议通过 COMPACT_TIME_OFFSET 安排在低峰时段执行。
参考
系统构架篇
- 01-《TDengine 整体架构全景》
- 02-《集群拓扑深度解析》
- 03-《MNode 内部机制深度解析》
- 04-《RPC 通信层深度解析》
- 05-《VNode 生命周期》
- 06-《RAFT 共识协议》
- 07-《端到端的消息流》
数据模型
- 01-《数据库创建与参数详解》
- 02-《超级表/子表/普通表》
- 03-《支持数据类型深度解析》
- 04-《TDengine Tag 设计哲学与 Schema 变更机制》
- 05-《TDengine 虚拟表实现原理》
存储引擎
- 01-《TDengine 存储引擎概览》
- 02-《TDengine MemTable 深度解析》
- 03-《TDengine WAL 预写日志机制》
- 04-《TDengine 数据文件格式》
- 05-《TDengine Commit 与 Flush 机制 》
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。