近似与精确的区别
uniq 系列用来统计不同值个数:uniq 用近似算法,省内存但有误差;uniqExact 精确但内存随基数线性增长。同一族里还有精度与资源特征不同的变体(如 uniqCombined、uniqHLL12),按精度要求与可用内存选择。
口径要写清楚
监控看板用近似值足够,对外出具的结算类数字应该用精确算法或直接落地去重表。把近似函数当精确值使用会产生对账差异,报表口径文档里要写清用的是哪一种算法,避免不同团队算出不同数字。
基本信息
| 近似 | uniq、uniqCombined、uniqHLL12,精度与资源特征不同 |
|---|---|
| 精确 | uniqExact,大基数时内存开销明显 |
| 组合 | uniq(x) 拿数量,groupUniqArray(x) 拿去重列表 |
| 内存控制 | 受 max_memory_usage 限制,超限直接报错 |
| 适用版本 | ClickHouse 各主流版本均支持 |
示例
示例
SELECT
toDate(ts) AS d,
uniq(user_id) AS approx_uv,
uniqExact(user_id) AS exact_uv
FROM events
GROUP BY d
ORDER BY d;
-- 数量与去重列表一起取
SELECT user_id, groupUniqArray(event_type) AS kinds, uniq(event_type) AS kind_cnt
FROM events GROUP BY user_id LIMIT 5;
-- 高基数场景:先分桶聚合,再对结果求和
SELECT sum(cnt) FROM (SELECT uniqExact(user_id) AS cnt FROM events GROUP BY toDate(ts));典型使用场景
- 看板指标:日活、去重 IP 这类近似统计
- 结算数字:需要精确对账时改用精确算法
- 去重列表:需要列出具体取值时用 groupUniqArray
- 高基数适配:数据量太大时先分桶再合并结果
- 口径核对:同一份数据用两种算法比对误差范围
函数选择
| 函数 | 特性 | 适用场景 |
|---|---|---|
| uniq | 近似,省内存 | 看板与趋势观察 |
| uniqCombined | 近似,精度与内存较均衡 | 通用近似统计 |
| uniqHLL12 | 近似,精度要求更高时使用 | 大规模去重 |
| uniqExact | 精确,内存随基数增长 | 结算与对账 |
| groupUniqArray | 返回去重后的取值列表 | 需要具体取值时 |
监控看板用近似统计足够;对外出具结算类数字时用精确算法或落地去重表,避免同一个指标在不同报表里出现两个版本的数字。
精确算法在高基数列上可能触发内存限制直接报错,必要时按时间或维度分桶聚合后再合并结果,而不是简单调大内存上限。