COUNT进阶(续):超大表去重计数的极致优化
关键词COUNT去重计数HyperLogLogbitmap近似查询SQL优化大家好我是小耶写功课只是为了我踩过的坑你们别再踩了上周我们讲了COUNT(*)在大表上的近似计数与HyperLogLog。这周继续聊COUNT的进阶话题——去重计数。你一定遇到过这样的需求“查一下昨天的独立访客数”“统计这周活跃设备量”直接用COUNT(DISTINCT user_id)10亿行表跑了半小时还没出结果怎么办去重计数的两种场景场景需求可接受误差运营报表、趋势图DAU、MAU1-2%财务、库存、对账精确金额、订单数0%不同场景对精度的要求完全不同。下面的优化手段按误差从大到小排列。方案一近似去重HyperLogLog—— 要快能接受1-2%误差HyperLogLog是一种概率算法用固定内存约16KB估算去重元素数量。原理将每个元素哈希统计哈希值二进制表示中前导零的最大长度通过这个信息推断去重总数。适用场景UV、DAU、独立IP、搜索词去重统计等。实现方式Redis HyperLogLog最常用import redis r redis.Redis() for user_id in logs: r.pfadd(daily_uv:2026-06-02, user_id) uv r.pfcount(daily_uv:2026-06-02) # 误差1%以内PostgreSQL hll扩展CREATE EXTENSION hll; SELECT hll_cardinality(hll_add_agg(hll_hash_integer(user_id))) FROM logs;方案二精确去重但用索引优化 —— 要准也要尽量快如果必须精确可以通过索引设计减少扫描量。技巧1覆盖索引COUNT(DISTINCT user_id)只需要user_id列如果(user_id)上有索引InnoDB可以直接扫描索引而不是全表大大减少I/O。-- 确保user_id有索引 CREATE INDEX idx_user_id ON logs(user_id); SELECT COUNT(DISTINCT user_id) FROM logs;技巧2使用GROUP BY代替DISTINCT在某些数据库中GROUP BY 外层COUNT有时比COUNT(DISTINCT)更快取决于优化器SELECT COUNT(*) FROM (SELECT user_id FROM logs GROUP BY user_id) t;实测对比1000万行user_id有索引写法耗时COUNT(DISTINCT user_id)12秒GROUP BY子查询11秒差异不大技巧3分桶计数如果数据分布均匀可以按某个维度分桶分别计数后求和。例如按日期分区每天分别COUNT(DISTINCT)再累加需要保证桶间无重复。方案三bitmap聚合 —— 极速精确去重限低基数场景如果去重的列基数很低比如只有几个值性别、状态、类型可以使用bitmap。每个值对应一个bit位多个值做OR/AND操作极快。实现方式使用PostgreSQL的bitmap扩展或MySQL的SET类型。适用场景标签系统、权限判断、漏斗分析中的“是否完成某动作”。方案四预计算/物化视图 —— 以空间换时间对于固定维度的去重统计如每日DAU可以提前计算并存储结果查询时直接读取。实现方式每日定时任务计算前一天的COUNT(DISTINCT user_id)存入统计表使用物化视图PostgreSQL支持MySQL需借助第三方工具方案实时性存储成本适用场景实时COUNT(DISTINCT)实时低小表或低频查询HyperLogLog实时极低可接受误差的高频查询预计算表非实时T1中固定报表、趋势图物化视图准实时可刷新中综合报表优化决策树真实案例某APP日活统计数据量每日约5000万独立设备ID要求实时展示当天DAU可接受1%误差方案使用Redis HyperLogLog每条日志pfadd实时pfcount结果内存占用约12KB/天响应时间10ms误差1.5%如果要求精确则采用T1预计算凌晨计算前一天的精确COUNT(DISTINCT device_id)存入MySQL白天查询直接读结果。价值总结去重计数的优化没有“银弹”关键在于根据业务对精度、实时性、成本的要求做出合理选择。HyperLogLog是误差容忍场景的利器bitmap适合低基数预计算适合固定报表。掌握了这些方案你就能在“快”和“准”之间找到最佳平衡点。小耶在手SQL 不愁还有什么想了解的欢迎留言小耶一定知无不言言无不尽……我们下次见~参考文献《HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm》Redis官方文档《HyperLogLog》《高性能MySQL》第4版第7章查询优化