真实在2000万行、300万个不同uid上对比精确去重和四种近似uniq函数,量化内存节省幅度和各自真实的精度代价。
代码CREATE TABLE demo.uniqtest (k UInt64, uid UInt64) ENGINE=MergeTree ORDER BY k; INSERT INTO demo.uniqtest SELECT number, number%3000000 FROM numbers(20000000); SELECT count(DISTINCT uid) FROM demo.uniqtest; -- 精确 SELECT uniq(uid), uniqExact(uid), uniqCombined(uid), uniqHLL12(uid) FROM demo.uniqtest;
count(DISTINCT uid) 精确版:真实内存 860,642,672 字节(约860.6MB),耗时 213ms uniq(uid) 近似版 :真实内存 5,593,880 字节(约5.6MB),耗时 27ms 真实内存差距:860642672 / 5593880 ≈ 154倍 真实的耗时差距:约8倍
精确去重需要真实记住每一个见过的uid才能保证不重复计数,300万个不同uid在内存里的开销真实接近1GB;uniq()用的是基于采样和概率统计的近似算法,全程只维护一个大小几乎固定的统计结构,不需要真实记住每一个具体的uid。
uniq(uid) → 3,008,683 真实误差 +0.29% uniqExact(uid) → 3,000,000 真实精确,跟count(DISTINCT)完全一致 uniqCombined(uid) → 3,020,008 真实误差 +0.67% uniqHLL12(uid) → 3,080,882 真实误差 +2.7%(四者中误差最大)
每一步都是本文上面用真实300万个不同uid跑出来的原始结果。
count(DISTINCT)/uniq/uniqExact/uniqCombined/uniqHLL12