列存的高压缩率来自 同列同质数据——整数 ID
用 Delta、时间戳用 DoubleDelta、监控指标用 Gorilla(Pelkonen
et al., VLDB 2015),字符串默认 LZ4/ZSTD。ClickHouse 在 DDL
用 CODEC() 声明 列级
编解码链;读路径逆序解压再进入向量化算子(第
4 篇)。
压缩比必须在本机同数据集上实测——本环境未安装 ClickHouse,正文不给未跑过的压缩倍数。
一、两层结构:专用编码 + 通用压缩
flowchart LR
RAW[原始列向量] --> SPEC[专用编码 Delta/Gorilla/...]
SPEC --> GEN[通用压缩 LZ4/ZSTD]
GEN --> BIN[.bin 压缩块]
| 层 | 例子 | 目的 |
|---|---|---|
| 专用编码 | Delta, Gorilla, T64 | 利用数据模式降熵 |
| 通用压缩 | LZ4, ZSTD | 字节级压缩 |
DDL:ts DateTime CODEC(DoubleDelta, LZ4) —
先 DoubleDelta,再 LZ4。
二、LZ4 与 ZSTD
| 算法 | 解压 CPU | 压缩率 | 场景 |
|---|---|---|---|
| LZ4 | 低 | 中 | 热数据、低延迟 |
| ZSTD | 较高 | 高 | 冷归档、带宽受限 |
默认列压缩由 compression 表 setting 或
config.xml 默认 codec 决定;列级
CODEC 覆盖。
与 storage 压缩 通用原理一致:无免费午餐,高率必付 CPU。
三、Delta / DoubleDelta
适合单调或平滑序列(时间戳、自增 ID)。存差分后数值更小、重复模式更多,再 LZ4/ZSTD 效果更好。
CREATE TABLE ts (
t DateTime CODEC(DoubleDelta, ZSTD),
id UInt64 CODEC(Delta, LZ4)
) ENGINE = MergeTree() ORDER BY t;不适合:高随机 UUID、已 hash 的均匀分布列——差分无规律,专用编码可能增大体积(工程判断,需本机验证)。
四、Gorilla 浮点编码
参考 Facebook Gorilla TSDB 论文;相邻浮点 XOR 后 leading/trailing zero 多,存 bit 长度与有效 payload。
可观测性 metrics 写入 ClickHouse 时常用(见 TSDB 内核 相关讨论)。
CREATE TABLE metrics (
ts DateTime CODEC(DoubleDelta, LZ4),
val Float64 CODEC(Gorilla, LZ4)
) ENGINE = MergeTree() ORDER BY ts;五、T64、FPC 与其它整型编码
官方 Compression codecs 列出
T64(bit-packing)、FPC 等;可用性依赖类型与版本。选型以
system.codec_usage(若启用)与实测为准。
六、LowCardinality
低基数 String/Enum 转 字典 + 索引;存储与 group by 可受益。过高基数字典膨胀,反而更差。
CREATE TABLE logs (
service LowCardinality(String),
msg String CODEC(ZSTD)
) ENGINE = MergeTree() ORDER BY (service, ts);七、与 PostgreSQL TOAST 对照
| 维度 | ClickHouse CODEC | PG TOAST |
|---|---|---|
| 粒度 | 整列所有 granule | 单行大字段 |
| 目标 | 扫描带宽 | 行大小上限 |
| 时机 | insert/merge | insert 超阈值 |
| 配置 | DDL 显式 | 存储参数/autovacuum |
PG 页面与 TOAST 对 OLTP 透明;ClickHouse 编码是 schema 设计决策。
八、Benchmark 方法(实验台账)
本机 ClickHouse 24.x 对比同表不同 CODEC 应记录:
- CPU 型号、
SELECT version() - 数据集行数、基数、列类型
- 至少 3 轮 insert,报告中位数
data_compressed_bytes - 固定
max_insert_block_size
SELECT
column,
compression_codec,
sum(data_compressed_bytes) AS compressed,
sum(data_uncompressed_bytes) AS uncompressed
FROM system.columns
WHERE database = currentDatabase() AND table = 'bench_codec'
GROUP BY column, compression_codec
ORDER BY column;未在本环境执行——正文不填压缩比数字。
可选:对同一查询比较 read_time /
ProfileEvents 中
CompressedReadBuffer* 与
OSIOWaitMicroseconds(需本机
EXPLAIN PIPELINE / query_log)。
九、选型建议(工程判断,非 benchmark)
| 数据特征 | 建议 CODEC |
|---|---|
| 时间戳 | DoubleDelta + LZ4/ZSTD |
| 缓慢变化 gauge | Gorilla + LZ4 |
| 枚举/服务名 | LowCardinality + ZSTD |
| 随机 UUID 字符串 | often 仅 ZSTD |
| 已压缩 JSON | NONE 或 ZSTD,避免无效 Delta |
十、读路径解压成本
Scan 列时必须解压 所有选中 granule 覆盖的压缩块;高压缩率 + ZSTD 可能 CPU-bound。物化视图预聚合可换空间换时间(第 10 篇规划)。
flowchart TB
MRK[Mark 定位块] --> READ[读压缩块]
READ --> ZSTD[ZSTD 解压]
ZSTD --> GOR[Gorilla 解码]
GOR --> VEC[ColumnVector]
十一、merge 与压缩
Background merge 重写 Part 时可 重新选择 codec(若 ALTER MODIFY CODEC);merge 是压缩策略变更的落地时机(第 6 篇)。
十二、边界
- 不讨论 GPU 压缩
- S3 磁盘加密层额外压缩不在此展开
十三、学术谱系:轻量编码 · Gorilla · 解压账单
| 阶段 | 文献 / 技术 | 本篇落点 |
|---|---|---|
| 经典 | RLE / 字典 / Delta 族 | CODEC 链前半段;LowCardinality |
| 2015 | Pelkonen et al., Gorilla, VLDB | 浮点 XOR;监控指标列 |
| 列存系统 | Abadi 等综述中的压缩清单 | 「同质列 → 高压缩」前提(第 01 篇三角) |
| 工程 | LZ4 vs ZSTD 通用层 | 率与 CPU 显式权衡 |
争论:追求最大压缩率(ZSTD 高档、重编码)vs 追求扫描吞吐(LZ4、轻 Delta)。论文常报压缩比;生产还要付 解压 CPU(第十节)与 merge 重写成本(第十一节)。
13.1 工程间隙
| 论文设定 | ClickHouse 24.x |
|---|---|
| 一次性 bulk load 后只读 | 持续 ingest + merge 反复编解码 |
| 单列理想分布 | 真实列混合高基数 UUID 与低基数枚举 |
| 内存常驻解压缓冲 | 云盘 + 有限 cache,解压可成瓶颈 |
13.2 开放问题
- 云盘场景下「压缩率拐点」在哪? 可检验:同列 LZ4 vs ZSTD 的端到端 scan CPU 与对象存储 GET 次数(入口:Gorilla VLDB’15;CH Compression)。
- LowCardinality 字典爆炸如何自动降级? 运维可见,算法侧仍开放。
上一篇:Part 格式
下一篇:向量化执行
参考资料
核心论文
- Pelkonen et al., Gorilla: A Fast, Scalable, In-Memory Time Series Database, VLDB 2015(A 级)。
- Abadi et al., Column-Stores vs. Row-Stores, SIGMOD 2008(压缩为列存栈一环;A 级)。
规范 / 源码 / 文档
- ClickHouse Documentation, Compression codecs(A 级)。
- ClickHouse Source, v24.3,
src/Compression/、src/DataTypes/Serializations/(A 级)。
编解码器链顺序
DDL 示例:value Float64 CODEC(Gorilla, ZSTD)
表示 先 Gorilla 专用编码,再 ZSTD
通用压缩。读路径逆序解压。
内置通用压缩:NONE、LZ4、ZSTD(及
level 变体)。专用编码见官方 Compression codecs
表。
Delta 族数学
对序列 \(x_1,\ldots,x_n\),Delta 存 \(d_i = x_i - x_{i-1}\)(首元素规则见实现)。DoubleDelta 对 \(d_i\) 再差分,适合时间戳等二阶平滑序列。
Gorilla 参考
Pelkonen et al., Gorilla: A Fast, Scalable, In-Memory Time Series Database, VLDB 2015。XOR 压缩相邻浮点值的 leading/trailing zero 相同前缀。
LowCardinality
内部维护字典 + 索引列;对低基数 String/Enum 减少存储与 group by 字典优化。与 Plain 编码选择属于 DDL 设计(非自动 TOAST)。
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【列存引擎内核】列存基础与 ClickHouse 架构
行存 vs 列存的带宽、压缩与向量化三角;ClickHouse Server 进程模型、线程池与 MergeTree 引擎家族地图;src/Storages 与 src/Processors 源码入口。对照 PG 行存与 LSM 写优化路径,版本锚定 ClickHouse 24.x LTS。
【列存引擎内核】MergeTree Part 文件格式
ClickHouse MergeTree Part 目录结构:columns.txt、checksums.txt、.bin、.mrk2、primary.idx 语义,Granule 与 Mark 的定位作用,Wide/Compact 布局与 MergeTreeDataPart 源码入口。版本锚定 24.x LTS。
【列存引擎内核】向量化执行引擎
ClickHouse Block 列向量 batch、IProcessor Pipeline 与 filter/project/aggregate 向量实现;对照 PostgreSQL 火山模型 ExecProcNode。源码入口 src/Processors、src/Columns。24.x LTS。
【列存引擎内核】查询读取路径
MergeTree SELECT 读路径:Mark Range 定位 Granule、PREWHERE 与 WHERE、Part 级并行与 max_threads。EXPLAIN indexes=1 解读方法。24.x LTS,无伪造 EXPLAIN 输出。