redis hyperloglog 的标准误差率为0.81%,这是由算法设计决定的固定理论值,与数据分布和规模无关,仅取决于桶数量(默认16384)和修正因子推导得出。

Redis HyperLogLog 的误差到底是多少?
Redis 的 PFCOUNT 返回的是一个**概率估算值**,不是精确计数。它的标准误差率是 0.81%,这是由算法设计决定的固定理论值(σ ≈ 0.0081),不是“看运气”的浮动误差。
这意味着:如果 PFCOUNT 返回 100,000,真实基数大概率落在 99,190~100,810 区间内。这个误差在 UV 统计、AB 测试分流、日志去重等场景中完全可接受——你本来也不需要知道“到底少了 3 个还是多了 7 个用户”,而要快速判断“是否突破百万量级”。
- 误差与数据分布无关:哪怕你反复插入同一个
user_id,只要哈希后服从均匀分布(Redis 的 MurmurHash3 满足),误差仍稳定在 0.81% 左右 - 误差不随数据量增大而恶化:统计 1 万或 1 亿,误差率都是 ~0.81%,这是它碾压
SET的核心优势 - 注意:误差是相对误差,不是绝对误差。基数越小,绝对偏差越小(比如基数为 100 时,误差约 ±1)
为什么不是 1%?0.81% 是怎么算出来的?
这个数字来自 HyperLogLog 的调和平均公式和桶数量配置。Redis 默认使用 2^14 = 16384 个桶(寄存器),每个桶记录对应分组哈希值的前导零最大位数。理论推导得出:标准差 σ ≈ αm / √m,其中 m 是桶数,αm 是修正因子(对 m=16384,αm≈0.7213)。代入得 σ ≈ 0.7213 / √16384 ≈ 0.0081。
简单说:0.81% 不是拍脑袋定的,是数学推导+工程权衡的结果——再增加桶数能略微降误差,但内存从 12KB 往上翻,性价比断崖下跌。
- Redis 7 没改这个值,也没提供调整精度的参数(不像某些数据库支持
precision配置) - 别试图用
PFADD多加几次同一元素来“校准”,没用:重复元素会被自动忽略,且不改变桶状态 - 如果你真需要
误差会叠加吗?合并多个 HyperLogLog 后还准不准?
不会叠加,反而更稳。PFMERGE 是无损合并操作:它把多个 HLL 的桶数组逐位取最大值,再用同一套公式重算基数。这相当于把原始数据“逻辑上合并在一个大 HLL 里处理”,误差仍保持 ~0.81%。
典型场景:每天一个 uv_20260301,月底用 PFMERGE uv_month uv_20260301 uv_20260302 ... 合并——最终结果的误差率和单日一样,不是 0.81% × 31。
- 但注意:
PFMERGE本身不校验输入键是否存在或是否为 HLL 类型,若误传了STRING键,会直接报错WRONGTYPE Operation against a key holding the wrong kind of value - 合并后原键不受影响,新键是全新结构,内存占用 = 所有源键中最大那个(稀疏/密集格式自动适配)
- 不要对同一组数据做多次
PFMERGE再PFCOUNT,纯属浪费 CPU:结果不会更准
什么时候该怀疑误差,而不是认命?
当观察到明显违背常识的偏差时,问题大概率不在误差率本身,而在用法错误。
-
PFCOUNT返回 0,但你知道至少插入过一次?检查是否用了错误的 key 名,或客户端连接了错误的 Redis 实例(常见于多环境共用配置) - 连续多天
PFCOUNT结果恒定不变?确认PFADD是否真的执行成功(返回值是 1 表示内部状态变更,0 表示元素已存在) - 合并后数值比各子集之和还小?不可能——HLL 并集估算值一定 ≥ 任一子集,若出现,说明某子集 key 被覆盖或误删
- 用
SCAN或KEYS查不到 HLL 键?正常:PFADD创建的 key 在空时可能不显式分配内存,首次写入后才真正存在
误差率 0.81% 是透明、稳定、可预期的背景噪音;真正要花时间排查的,永远是数据链路中的那几个具体环节。










