去重计数的三条路
去重计数有三种实现:精确的 count distinct 简单但代价高;近似算法(如 HyperLogLog)资源占用低但有误差;位图(bitmap)精确且支持交并运算,适合基数中等又需要人群圈选的场景。选哪一种取决于精度要求、数据规模与是否需要集合运算。
基本信息
| 精确方案 | count distinct,结果准确但大表开销高 |
|---|---|
| 近似方案 | HyperLogLog 等,误差可控,适合超大基数 |
| 位图方案 | bitmap,精确且支持交并,受基数上限约束 |
| 常见引擎 | Doris 与 StarRocks 内置 bitmap,Hive 用近似函数 |
| 前提条件 | 去重实体定义必须统一,否则算法再准也对不齐 |
典型使用场景
- UV 与活跃用户:海量日志上的用户去重,可用近似方案换性能
- 人群圈选:营销需要多个标签的交并运算,位图最直接
- 留存与交集分析:今日活跃与昨日活跃求交集,位图一次运算完成
- 对外精确口径:披露类数字要求准确,用精确去重或位图
- 性能治理:count distinct 导致 shuffle 过大时改近似或预聚合
精确去重与位图并集
精确去重与位图并集
-- 精确去重:结果准确,大表开销高
SELECT count(DISTINCT user_id) AS uv
FROM dwd_active_user
WHERE dt = '2026-10-12';
-- Doris 位图:周活等于 7 天位图的并集
SELECT bitmap_count(bitmap_union(user_bitmap)) AS wau
FROM dws_user_bitmap_day
WHERE dt BETWEEN '2026-10-05' AND '2026-10-11';三种方案对比
| 方案 | 精度 | 成本 | 适用场景 |
|---|---|---|---|
| count distinct | 精确 | 高,需要大量洗牌运算 | 中小数据量、对外精确口径 |
| HyperLogLog | 近似 | 低,空间可控 | 超大基数且可容忍误差 |
| bitmap | 精确 | 中,受基数上限约束 | 人群圈选、集合交并运算 |
用近似方案时把误差写进口径:近似结果不能与精确口径直接比对,报表上标注算法与误差范围,避免被当成数据故障。
位图的基数上限是硬约束:用户量或设备量超过引擎支持范围时构建会失败,需要先分桶或改回近似方案,不要等到任务报错才发现。