列式存储为什么压缩率高?字典、RLE和Delta编码分别适合什么数据?
本文目录
面试怎么回答
我会先区分列式布局、编码和通用压缩。列式把同一字段集中,字典用编号替代重复值,RLE压缩连续重复段,Delta利用相邻数值差较小的特点;编码后的字节还可以交给压缩算法。效果取决于基数、排序和数据类型,高基数字典不一定划算。验收除了文件大小,还要看写入与解码CPU、扫描延迟及读取器兼容性。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
同样的数据,为什么按列存放后能小很多?只回答“用了Snappy或ZSTD”还不完整。国家、状态、时间戳这些列各有规律,字典、游程和差分编码利用的正是这些规律,而不是所有字段都套同一招。
列式布局让相似值集中,编码利用重复或差分结构,通用压缩再处理编码后的字节;收益取决于数据分布。
列式布局先把相似数据放到一起
行式记录把一行的各种字段排在一起,列式则让同一字段的值集中组织。国家代码之间、状态之间往往比一整行不同类型字段更相似。
这给编码提供了机会,但不保证每一列都能大幅缩小。随机标识、已经压缩的二进制和高熵文本,可能没有多少可利用的重复规律。
另外,查询只读少数列时可以减少无关列的读取,这属于列裁剪收益,不要全部归因于压缩率。
字典编码:重复值用编号表示
假设一列只有“待支付、已支付、已取消”三种值,可以保存一份字典,再用较小编号表示各行状态。
节省来自值反复出现,而不是编号本身神奇。如果几乎每行都是不同长字符串,字典本身也会很大,管理开销可能抵消收益。
Parquet的写入实现可能在字典过大时回退到其他编码;实际采用什么,要看文件元数据与写入器行为,不能仅凭开启字典选项就认定整列一直使用字典。
RLE与Delta,利用的是不同规律
RLE即游程编码,适合连续重复,例如A、A、A、B、B可以用“若干个A、若干个B”的方式表达。相同值被打散时,连续段变短,效果可能下降。
Delta关注相邻数值差,例如1000、1001、1002的差值是1、1。实际格式还会结合块、位宽等细节,概念示例只说明为什么小差分有机会减少表示成本。
排序可能同时改善连续重复和差分规律,但排序也有写入代价,而且一个排序顺序不一定同时优化所有列。应围绕主要查询与数据分布权衡。

编码与压缩算法,可以叠加但不是同义词
字典、RLE和Delta属于数值或结构的表示方式;Snappy、ZSTD等通用压缩算法进一步处理字节序列。
因此“用了字典就不用压缩”和“换了压缩算法就不需要考虑排序”都不准确。Parquet具体页面采用的编码和压缩方式,应按格式及读写实现确认。
这里也不能直接推导某个算法一定更快。压缩后读取字节减少,可能节省I/O;编码与解码又要消耗CPU,最终瓶颈取决于任务。
一个典型场景:随机ID开启字典,收益并不理想
比如团队把所有字符串列统一强制按低基数思路调优,状态列明显变小,随机请求ID却没有预期收益,写入CPU还上升。
最初怀疑压缩算法失效,查看列分布后发现请求ID几乎逐行不同,根本没有足够重复值可复用。旧测试只使用少数状态枚举,无法代表高基数字段。
修复应按列分析基数、长度和排序特征,查看实际编码,允许合适回退,而不是继续扩大字典预算。评估时同时比较体积、写入内存和查询延迟。
即使高基数列在某个数据集上仍有收益,也要把它视为实测结论,而不是从一条经验推广到所有随机标识。
验收应覆盖读与写两端
选择低基数状态、递增时间戳、随机ID和长文本等代表列,固定数据规模与布局,比较不同配置的文件大小和处理成本。
同时确认读取引擎支持生成的编码与格式版本。文件能写成功,不代表所有下游读取器都能正确高效地解析。
面试里不必背完每一种编码的二进制规范。讲清楚“重复集合、连续重复、小差分”三种不同机会,再说明何时失效,就能把机制与真实数据连接起来。
资料与适用边界
机制以所链接版本为准;业务示例用于说明判断方法,不代表作者真实项目或已验证的生产性能。