关键词:COUNT;HyperLogLog;近似计数;基数估算;大数据
摘要
当表数据量达到千万甚至亿级时,精确的 COUNT(DISTINCT col) 往往非常缓慢。本文介绍一种概率性算法------HyperLogLog,它可以在极小的内存开销下估算唯一值的数量,误差控制在2%以内。结合Redis、PostgreSQL等实现方式,帮助数据分析师在超大表场景下快速获得近似统计结果。
大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!
上周讲了 COUNT(*) 优化,今天聊一个更进阶的话题:当我们需要统计唯一值数量(如UV、独立用户数)时,传统的 COUNT(DISTINCT col) 在超大表下非常慢。这时可以用近似计数。
1 名词解释
- HyperLogLog:一种概率性算法,用极小内存估算集合中唯一值的数量,误差通常在2%以内。
- 基数(Cardinality):集合中不重复元素的个数,如UV、独立用户数。
- 近似计数:牺牲少量精度换取极致性能,适合对精确度不敏感的场景。
2 实际运用
2.1 传统 COUNT(DISTINCT) 的问题
SELECT COUNT(DISTINCT user_id) FROM orders;
在千万级表中,这个查询需要创建临时表去重,内存不足会写磁盘,耗时可能几十秒甚至分钟级。
2.2 HyperLogLog 实现
- Redis :
PFADD daily_uv user123,PFCOUNT daily_uv获取估算值。 - PostgreSQL :
CREATE EXTENSION hll;然后使用hll_add_agg等函数。 - 金仓数据库 :兼容PostgreSQL的
hll扩展,用法相同。 - MySQL:没有内置,可以通过存储过程模拟或调用Redis。
2.3 实战示例(Redis)
bash
# 添加用户ID
PFADD uv_20260519 user123 user456 user789
# 获取估算UV数
PFCOUNT uv_20260519
2.4 适用场景
- 适用:运营大屏、趋势分析、预估报告,对精确度不敏感(允许1-3%误差)。
- 不适用:财务结算、精准营销券发放等需要精确计数的场景。
3 实测对比(1000万UV)
| 方法 | 耗时 | 内存占用 |
|---|---|---|
COUNT(DISTINCT user_id) |
25秒 | 临时表巨大 |
| Redis HyperLogLog | 2毫秒 | 12KB |
4 价值总结
- 千万级
COUNT(DISTINCT)可能耗时数十秒,而HyperLogLog可将时间压缩到毫秒级,内存占用仅KB级别。 - 学会近似计数,你就能在业务指标监控、用户行为分析等场景中,用极低成本获取趋势数据,避免数据库被压垮。
- 如果业务可以接受2%左右的误差,HyperLogLog是替代精确去重的绝佳方案。
小耶在手,SQL不愁。
还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽......我们下次见~
参考文献
1\] Redis官方文档:HyperLogLog \[2\] PostgreSQL HLL扩展文档 \[3\] 《高性能MySQL》第4版,第7章"查询优化"