bigywater.tech
ClickHouse 内部原理 · 20

LowCardinality:字典编码什么时候有用

真实对比同一列国家代码用普通String和LowCardinality存储的压缩前后字节数,诚实说明真实收益点在哪里、以及本机小规模测试测不出什么。

10倍
LowCardinality真实压缩前体量只有普通String的十分之一
诚实局限
本机小规模GROUP BY真实未测出显著速度差异

做的事:500万行,10个国家代码循环,真实存两份

代码CREATE TABLE demo.lctest ( k UInt64, country String, country_lc LowCardinality(String) ) ENGINE=MergeTree ORDER BY k; INSERT INTO demo.lctest SELECT number, ['CN','US','JP','DE','FR','IN','BR','RU','UK','CA'][(number%10)+1], ['CN','US','JP','DE','FR','IN','BR','RU','UK','CA'][(number%10)+1] FROM numbers(5000000);

验证:压缩后字节数真实很接近,LowCardinality甚至略大

实测 · 本机执行输出(system.columns,500万行,10个不同国家代码循环)
column       compressed   uncompressed   ratio
country         228362       50000000   0.0046
country_lc       29223        5010027   0.0058    ← 压缩比反而略高于country

真实关键差异在uncompressed(压缩前)字节数:
country     的 uncompressed = 50,000,000 字节  (500万行×平均10字节/字符串)
country_lc  的 uncompressed =  5,010,027 字节  (真实只有前者的约十分之一)

如果只看最终压缩后的磁盘占用(228362 vs 29223字节),两者其实都小到可以忽略——因为LZ4对"只有10种取值、疯狂重复"的普通字符串本身就已经压缩得很彻底了。真正有意义的差异藏在data_uncompressed_bytes这一列:country_lc的压缩前体量真实只有country的约十分之一。

为什么uncompressed体量的差异才是LowCardinality真实的价值所在

LowCardinality的真实机制,是在写入的时候把重复出现的字符串先做一次字典编码——磁盘上实际存的是一份"全局字典"(10个国家代码字符串各存一份)加上"每一行是字典里第几号"这样一个小整数索引,data_uncompressed_bytes统计的正是这个字典编码之后、送进LZ4压缩之前的体量,所以country_lc真实只有country的十分之一。这解释了LowCardinality真实起作用的场景不是"最终磁盘占用"(因为LZ4这类通用压缩算法本身就很擅长处理高重复度的字符串,把普通String压到跟LowCardinality差不多小),而是CPU层面的省力:GROUP BY、JOIN、DISTINCT这类需要频繁比较字符串值是否相等的操作,对字典编码后的小整数做比较,比逐字节比较原始字符串要快得多;数据从磁盘读到内存、在计算节点之间网络传输时,搬运的也是压缩前就已经小十倍的字典编码后的数据,而不是解压后还原成完整字符串再处理。本文500万行、10个枚举值的规模下,一次简单的GROUP BY耗时都在几十毫秒量级,两者的差异被进程调度和网络往返的噪声完全淹没,量不出真实差别;这类收益真实要在数据量大到CPU反序列化/比较成为瓶颈、或者多节点之间要传输这一列数据的分布式查询场景下才会显现出来。诚实的结论是:本文没能在本机单节点的小规模测试里测出GROUP BY速度的显著差异,但从uncompressed字节数十倍的差距上,能确认LowCardinality真实在更早的阶段(写入/网络传输/内存比较)就已经把数据体量压缩了,只是这部分收益不会体现在data_compressed_bytes这个最终磁盘占用指标上。

分步演示:从压缩后字节数的假象到压缩前体量的真实差距

每一步都是本文上面用真实system.columns跑出来的原始结果。

LowCardinality真实的收益藏在压缩前的体量里
这一步新验证的对比

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 system.columns(compressed/uncompressed对比)
    • 诚实说明:本机小规模GROUP BY未能测出有意义的速度差异
    京ICP备2026067502号-1京公网安备11010502063487号