bigywater.tech
ClickHouse 内部原理 · 18

Column Compression:一列数据是怎么被压缩的

真实给同一列连续整数分别用LZ4、ZSTD、Delta+LZ4、NONE编码存一份,对比真实压缩后的字节数差距。

200倍差距
同样200万行连续整数,NONE到Delta+LZ4的真实压缩比差距
两段式管线
Delta真实负责转换数据形状,LZ4真实负责通用压缩

做的事:同一列连续整数,真实用4种编码各存一份

代码CREATE TABLE demo.codec1 ( k UInt64, v_default UInt64 CODEC(LZ4), v_zstd UInt64 CODEC(ZSTD(3)), v_delta UInt64 CODEC(Delta, LZ4), v_none UInt64 CODEC(NONE) ) ENGINE=MergeTree ORDER BY k; INSERT INTO demo.codec1 SELECT number, number, number, number, number FROM numbers(2000000);

验证:同样的数据,4种编码真实压出了100倍的差距

实测 · 本机执行输出(system.columns,200万行连续整数0..1999999)
SELECT column, data_compressed_bytes, data_uncompressed_bytes,
  round(data_compressed_bytes/data_uncompressed_bytes,4) AS ratio
FROM system.columns WHERE table='codec1';

column      compressed   uncompressed   ratio
v_none        16006125       16000000   1.0004   ← 不压缩,反而比原始略大(块头开销)
v_default      8009940       16000000   0.5006   ← LZ4默认,只压掉一半
v_zstd         2052891       16000000   0.1283   ← ZSTD(3),压到12.8%
v_delta          80324       16000000   0.0050   ← Delta+LZ4,真实压到0.5%

同一列数据,从不压缩(16MB)到Delta+LZ4(80KB),真实相差约200倍;即便是同为通用压缩算法的LZ4和ZSTD相比,ZSTD(3)也真实比LZ4默认压缩比高出近4倍——但两者都远远比不上专门为这份数据形状设计的Delta编码。

为什么Delta能压到LZ4的1/100

LZ4和ZSTD都属于通用字节流压缩算法——它们不知道这一列存的是"连续递增的整数",只能在字节层面找重复模式;对于0,1,2,3...这样每个值都用完整的8字节存储、相邻数字的二进制表示又差异很大(比如255和256的字节完全不同)的数据,通用压缩算法能挖掘的冗余非常有限,LZ4只压到50%左右。而Delta是一种前处理编码(codec),真实做的事情很简单:把"存储原始值"换成"存储相邻两个值的差"——本文这份数据里,相邻两个数的差永远是1,一列200万个1,交给后面的LZ4去压缩,那就是极致的重复模式,几乎可以无限压缩。这也是ClickHouse把编码设计成"CODEC(Delta, LZ4)"这种两段式管线的原因:第一段(Delta/DoubleDelta/Gorilla这些)负责把数据的统计特性转换成更容易被压缩的形状,第二段(LZ4/ZSTD)负责真正的通用压缩,两者组合使用而不是二选一。真实的建议是:自增ID、时间戳这类单调或者准单调的列用Delta,温度/价格这类缓慢波动的浮点数用Gorilla(下一篇会真实验证),完全无规律的数据老老实实用ZSTD或LZ4,不要指望Delta对随机数据也能有魔法效果——对随机数据做差分,得到的还是随机数据,不会凭空产生可压缩的重复模式。

分步演示:从不压缩到Delta编码,200倍的真实差距

每一步都是本文上面用真实system.columns跑出来的原始压缩字节数。

同一份数据,四种编码真实压出200倍差距
这一步新验证的编码

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 system.columns(data_compressed_bytes列)
    • 真实对比 CODEC(NONE/LZ4/ZSTD(3)/Delta,LZ4) 四种编码
    京ICP备2026067502号-1京公网安备11010502063487号