知其然,知其所以然
数据编码与压缩 2026-10-12

怎么公平地比较编码与压缩:测试数据、指标与重复次数

本系列的方法篇:五个合成数据集、计时用中位数且机器要空闲、同一个压缩结果换基准压缩比从 5.42× 变成 6.66×、每条单独压缩只有 1.25× 而整批压缩是 5.40×、数据越重复压缩比越高、多线程压缩大数据输出会和单线程不同。

编码 压缩 基准测试 测试方法 zstd Python 真实验证 动画演示
数据编码与压缩 2026-10-12

JSON 的真实开销:字段名、数字文本、转义与大整数

量 JSON 的真实开销:2 万条商品记录里键名占 26.1%、字符串值占 59.3%、数字只占 5.7%;中文用 ensure_ascii=True 翻倍;node 会丢 2^53+1 的最后一位;orjson 比标准库快 2 到 8 倍;缩短键名省 15.2% 的原始字节,zstd 压缩后只剩 3.3%。

编码 JSON 字节构成 orjson 浮点 Unicode 大整数 zstd Python 真实验证 动画演示
数据编码与压缩 2026-10-12

MessagePack 比 JSON 小多少,哪些数据几乎没变小

实测 MessagePack 对 JSON:未压缩小 11.9%–27.2%,但 products(字符串多)用 zstd 压缩后 MessagePack 反而大 6.2%,数值多的 timeseries 小 15.3%;速度比标准库 json 快、比 orjson 慢;整数键、bytes 能保留,tuple 变 list,2^64 溢出。

编码 MessagePack JSON 压缩 orjson 字节构成 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

整数怎么变成更少的字节:varint、ZigZag 与定长

自己写 varint 和 ZigZag 并与 protobuf 库逐值对照:int32 的 -1 要 10 字节、sint32 只要 1 字节;大数值(时间戳)用 varint 比定长 4 字节还大;时间戳列先差分再压缩从 46185 降到 9005 字节;已知小数位数时乘 100 取整比 float64 小得多。

编码 varint ZigZag Protobuf 差分编码 整数 浮点 zstd Python 真实验证 动画演示
数据编码与压缩 2026-10-12

Protobuf 的字节长什么样:逐字节拆解与 schema 演进

逐字节拆解一条 Protobuf 记录并与 protoc --decode_raw 核对:字段头 1 字节 = 字段号和类型,字段号 16 起多 1 字节(2 万条多 299953 字节);Protobuf 比 JSON 小 32.2%,但 zstd 压缩后反而大 3.3%;加字段、改名新旧兼容,int64 的大值被 int32 读成 0;默认值不写出。

编码 Protobuf wire format 字段号 schema 演进 默认值 protoc Python 真实验证 动画演示
数据编码与压缩 2026-10-12

有 schema 与无 schema:体积、速度与调试成本

有 schema 和无 schema 的对比:Protobuf 在赋值时拦住类型错误但不拦缺字段;没有 schema 看不出字符串和嵌套消息的区别;把键名挪到表头的 JSON 数组比 Protobuf 只大 2.4%、压缩后还更小;三种格式遇到翻转的字节都大多静默解出错误的值;Protobuf 解码到内存 11 MiB 对 JSON 36 MiB。

编码 Protobuf JSON schema MessagePack orjson 内存 损坏 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

只读一个字段要解多少:各格式的解码成本

只想读一个字段或一条记录要解多少:整批解析 4–43 ms,带偏移索引的逐条存储只要 0.001–0.003 ms;求一列的和 Protobuf 3.9–6.3 ms 对 JSON 42.8 ms;字节级扫描 JSON 会被空白格式和嵌套同名键骗;压缩分块越大压缩比越高、点查越慢。

编码 部分解码 偏移索引 Protobuf JSON MessagePack zstd 分块 随机访问 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

行式与列式布局:同样的数据换个排列为什么压缩得更小

同样的数据换一种排列:列式比行式 zstd-3 小 33.2%;每列单独看,url 能压 94.67×、title 只有 2.96×;给每列配专用编码(字典、差分、整数分)再压缩共 685160 字节,比行式小 48.5%;读 price 一列只要 1.3 ms 对 57.7 ms;分块越小列式优势越小。

编码 列式存储 行式 压缩 字典编码 差分 zstd Parquet Python 真实验证 动画演示
数据编码与压缩 2026-10-12

压缩比的天花板:香农熵与各数据集的理论下限

压缩比的天花板:随机字节熵 8 bit/字节谁也压不动;products 文本 0 阶熵下限 673018 字节、实际 xz-9 做到 113026;已知前 4 个字节条件熵降到 0.734;16.5 万个短字节串压缩后一个都没变短;概率很偏的信源 zstd 离理论值还差 66.5%。

压缩原理 香农熵 条件熵 不可压缩 鸽巢原理 zstd xz bz2 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

Huffman 编码:出现越多的符号用越短的码

自己写 Huffman:abracadabra 压成 23 位(定长 88 位);products 文本平均码长只比熵多 0.53%,但压缩比只有 1.55×;分布偏时(0.9/0.1)Huffman 比熵多 113.2%;只做 Huffman 的 zlib 是 1.55×,加上 LZ77 匹配是 4.90×。

压缩原理 Huffman 熵编码 规范Huffman deflate Python 真实验证 动画演示
数据编码与压缩 2026-10-12

LZ77:把重复的内容换成"往回看多远、复制多长"

自己写 LZ77 并解回原文验证:products 文本 95.9% 的字节被匹配覆盖,匹配距离多在 4 KiB 以上;窗口 256 字节估算 79440、窗口 128 KiB 估算 28042;搜索越努力越小;全零数据 zlib 最多约 1000×、zstd 可到 32466.8×;LZ77 加 Huffman 的估算与 zlib 级别 9 只差 1%。

压缩原理 LZ77 滑动窗口 哈希链 deflate 重叠匹配 zstd Python 真实验证 动画演示
数据编码与压缩 2026-10-12

gzip 内部:一个 deflate 块里的 LZ77 加 Huffman

自己写 inflate 解码真实的 deflate 流:gzip 比裸 deflate 多 18 字节(10 头 + 8 尾);products 1 MiB 压成 8 个动态块、95.4% 的输出由匹配产生;块头只占 0.2%;短输入或随机数据会改用固定码或存储块,最多多几个字节;gzip.GzipFile 默认会把当前时间写进头里。

压缩原理 gzip deflate inflate 动态Huffman 块 CRC32 Python 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号