approx_count_distinct适用于大数据量(千万级+)、高基数去重列(如user_id)、可接受±1%误差的olap场景,如实时dau统计、广告人群覆盖预估;它基于hyperloglog算法,内存固定、速度快,但不支持blob/clob/json类型,且需避免与count(distinct)混用或在低基数字段上使用。

APPROX_COUNT_DISTINCT 适合什么场景
当表数据量超过千万级、去重列基数高(比如 user_id、device_id)、且业务能接受 ±1% 误差时,APPROX_COUNT_DISTINCT 是比 COUNT(DISTINCT) 更现实的选择。它不是“凑合用”,而是专为吞吐优先的 OLAP 场景设计——比如实时看板统计 DAU、广告平台预估覆盖人群、日志系统快速探查字段唯一性分布。
不同数据库里怎么写才不报错
语法差异明显,不能直接跨库复用:
- Oracle 和 PostgreSQL(14+)支持标准写法:
SELECT APPROX_COUNT_DISTINCT(user_id) FROM events; - MySQL 目前(截至 2026 年)仍不原生支持该函数,需改用
COUNT(DISTINCT)+ 子查询预聚合,或接入外部近似算法 UDF - BigQuery 和 Spark SQL 支持但函数名带下划线:
APPROX_COUNT_DISTINCT(注意大小写),且对NULL的处理一致:自动跳过 - 如果字段是
BLOB、CLOB或JSON类型,所有数据库都会拒绝 —— 必须先转成字符串或提取标量子字段
为什么有时候结果偏差超预期
偏差放大通常不是算法问题,而是数据结构或使用方式导致:
- 把
APPROX_COUNT_DISTINCT套在未过滤的全量表上跑,而实际业务只关心最近 7 天——应先加WHERE dt >= '2026-08-20'再近似,否则噪声数据拉高误差率 - 对低基数字段(比如只有 ‘iOS’/‘Android’/‘Web’ 三种值)用近似函数,反而不如精确计算快,还失去确定性
- 在
GROUP BY中混用精确与近似聚合,比如同时写COUNT(*)和APPROX_COUNT_DISTINCT(user_id),某些引擎会强制降级为全哈希路径,失去性能优势 - 分区表没指定分区键,导致扫描全部分区文件,近似过程变成“近似地扫全表”
和 COUNT(DISTINCT) 混用时要注意什么
不能在一个 SELECT 中混用两者来“交叉验证”,因为执行计划可能完全不同:
-
APPROX_COUNT_DISTINCT通常走采样 + HyperLogLog 类算法,内存固定、不落地 -
COUNT(DISTINCT)在大数据下大概率触发Using temporary; Using filesort,依赖磁盘临时表 - 若必须对比,应分别执行、禁用缓存(如加
SQL_NO_CACHE),并确认两者的 WHERE 条件、JOIN 逻辑、分区裁剪完全一致 - 上线前务必用小样本(比如抽样 0.1% 数据)人工校验误差范围,避免在报表中突然出现“DAU 少报 50 万”这类不可解释波动
真正容易被忽略的是:近似函数不解决数据倾斜问题。如果 90% 的 user_id 都集中在某几个 channel 下,APPROX_COUNT_DISTINCT 在分组后仍可能因局部哈希冲突导致某组误差陡增——这时得配合预聚合或分桶修正。











