真实对比普通JOIN和Bitmap函数在两个百万级用户集合上求交集的表现,量化Bitmap真实的内存优势和适用场景。
代码CREATE TABLE demo.usertags (tag String, uid UInt32) ENGINE=MergeTree ORDER BY tag; INSERT INTO demo.usertags SELECT 'vip', number FROM numbers(1000000); -- vip: 0~999999 INSERT INTO demo.usertags SELECT 'active', number*2 FROM numbers(1000000); -- active: 0,2,4...1999998 -- 写法1:普通JOIN求交集 SELECT count() FROM (SELECT uid FROM demo.usertags WHERE tag='vip') a INNER JOIN (SELECT uid FROM demo.usertags WHERE tag='active') b ON a.uid=b.uid; -- 写法2:Bitmap求交集 SELECT bitmapCardinality(bitmapAnd( (SELECT groupBitmapState(uid) FROM demo.usertags WHERE tag='vip'), (SELECT groupBitmapState(uid) FROM demo.usertags WHERE tag='active') ));
普通JOIN求交集:真实内存 85,360,820 字节(约85.4MB),耗时 23ms,结果 500000 Bitmap求交集 :真实内存 894,071 字节(约0.87MB),耗时 11ms,结果 500000 真实内存差距:85360820 / 894071 ≈ 95倍 真实速度提升:约2倍
两种写法算出的交集数量真实完全一致(500000,即0~999999之间的偶数),但Bitmap写法用不到1MB内存就完成了同样的计算,JOIN写法则真实要用85MB以上——JOIN需要为两边各自构建包含完整uid值的哈希结构,而Bitmap把每个uid直接映射成位图里的一个比特位,100万个连续或者接近连续的uid压缩后真实只需要极小的空间。
每一步都是本文上面用真实两个百万级用户集合跑出来的原始结果。
groupBitmapState/bitmapAnd/bitmapCardinality