approx_count_distinct仅在千万行以上、高基数列(如800万不同user_id)时显著快于count(distinct),内存恒约12kb、误差≤2%;低基数、小表、null未过滤、语法错误或索引不匹配时反而更慢更不准,且不适用于需精确值的财务对账等场景。

APPROX_COUNT_DISTINCT只在千万行+高基数列才真快
它不是万能加速器,而是专为“大表+高区分度字段”设计的近似计数工具。比如 user_id 有 800 万个不同值、表总行数 2 亿,这时 APPROX_COUNT_DISTINCT(user_id) 才比 COUNT(DISTINCT user_id) 明显快——内存恒约 12KB,不建全量哈希表,避免磁盘 spill。
但以下情况它反而更慢:
-
user_id实际只有 12 个取值(低基数),算法开销白加一层 - 表才 5 万行,I/O 和解析耗时已远超聚合本身
- 字段含大量
NULL,且WHERE没提前过滤,等于近似地扫一堆无效数据
语法和兼容性踩坑点必须盯死
APPROX_COUNT_DISTINCT 名字带下划线、大小写不敏感,但拼错一个字符就报错;只支持 SQL Server 2019+,且数据库兼容级别必须 ≥ 150:
ALTER DATABASE [YourDB] SET COMPATIBILITY_LEVEL = 150;
常见翻车:
- 写成
APPROX_COUNT_DISTINCT()(空括号)→ 报错 “An aggregate may not appear in the set list...” - 在 SQL Server 2017 或更低版本执行 → 报错 “'APPROX_COUNT_DISTINCT' is not a recognized built-in function name”
- 对
datetime2字段直接去重,却忘了先CAST(oper_time AS DATE),导致基数虚高、误差放大 - 传了第二个参数(如误差精度)→ 直接语法错误(SQL Server 版不支持该参数)
WHERE 条件写法决定它快不快
APPROX_COUNT_DISTINCT 快,不代表整条查询快。如果 WHERE 导致全表扫描,它就是在“近似地扫全表”。关键看索引是否覆盖查询路径:
- 错误写法:
WHERE DATE(oper_time) = '2026-09-10'→ 时间索引失效,每行都算函数 - 正确写法:
WHERE oper_time >= '2026-09-10' AND oper_time → 可走索引范围扫描 - 只在
(user_id)建索引,但查询带WHERE biz_type = 'login' AND oper_time >= '2026-09-01'→ 索引无法覆盖,仍要回表或全扫
建议联合索引按 WHERE 条件顺序建,例如 (biz_type, oper_time, user_id)。
误差控制和适用场景别越界
官方保证:97% 概率下误差 ≤ 2%。比如真实值 1 亿,结果通常落在 9800 万~1.02 亿之间。这足够用于 DAU 监控、AB 实验分流、报表趋势分析——但绝不能用于财务对账、合同结算、审计口径等要求精确值的场合。
另外注意类型限制:不支持 image、ntext、sql_variant;对 varchar(max) 或 JSON 字段,得先 CAST 成普通字符串再用。
最常被忽略的一点:它自动忽略 NULL,但如果你的业务逻辑本应把 NULL 视为一个有效取值(比如“未填性别”算一种状态),那这个“忽略”本身就是语义偏差,不是性能问题,而是结果错。










