必须配对使用hll_init+hll_merge+hll_estimate三件套,因snowflake的hll非标量函数;漏任一环报错或返回null;hll_init需非null输入;hll_merge为group by专用聚合函数;hll_estimate仅接受binary型输入。

直接用 HLL 函数就行,但必须配对使用 hll_init + hll_merge(聚合阶段)+ hll_estimate(最终取值),不能只写一个函数就完事。
为什么不能直接写 COUNT(DISTINCT x) 替换成 HLL?
Snowflake 的 HLL 不是开箱即用的标量函数,它是一套三件套:先用 hll_init 把原始值转成 HLL sketch,再用 hll_merge 合并多个 sketch,最后用 hll_estimate 解出近似基数。漏掉任意一环都会报错或返回 NULL。
-
hll_init(x)必须传非 NULL 值,NULL 会被跳过 —— 所以hll_init(COALESCE(col, 'null_placeholder'))比直接hll_init(col)更稳 -
hll_merge是聚合函数,只能在GROUP BY中用,不能出现在 WHERE 或 SELECT 非聚合列里 -
hll_estimate接收的是hll_merge的输出,类型为BINARY,不能直接CAST或参与算术运算
HLL 和 APPROX_COUNT_DISTINCT 选哪个?
如果只是单层聚合、不关心中间 sketch 复用,APPROX_COUNT_DISTINCT(col) 更简单,语义和性能接近 HLL 三件套,误差率也都在 ~1.6% 左右。但它不可拆解 —— 你没法把今天和昨天的 sketch 合并,也没法做分组后二次聚合。
- 要支持增量合并(比如按天计算再合到月)、或需要跨多个查询复用 sketch,必须用
hll_init/hll_merge/hll_estimate -
APPROX_COUNT_DISTINCT在小数据集上可能比精确COUNT(DISTINCT)还慢,因为要初始化 sketch 结构;数据量 > 1M 行时优势才明显 - 两者都对高基数字符串友好,但若列含大量重复短字符串(如状态码
'200'、'404'),HLLsketch 占用空间反而比APPROX_COUNT_DISTINCT略大
实际写法:带条件的近似去重怎么写?
比如 “统计每个城市中付费用户(is_paying = true)的近似 UV”,不能在 hll_init 外套 FILTER(Snowflake 不支持聚合函数的 FILTER 子句),得用 CASE:
SELECT city, hll_estimate(hll_merge(hll_init(CASE WHEN is_paying THEN user_id END))) AS approx_uv FROM users GROUP BY city;
注意:CASE 分支返回 user_id 或 NULL,hll_init(NULL) 会跳过,等效于过滤;别写成 CASE WHEN is_paying THEN hll_init(user_id) —— 那会导致非付费行传入 NULL 给 hll_init,语法错误。
真正容易被忽略的是 sketch 生命周期:一旦存成表字段(比如用 hll_merge 结果写入物化视图),后续想加新数据就得再调一次 hll_merge,而不是重新跑全量 hll_init。这一步没想清楚,后面就只能重建。










