首页/数据/SQL 速查/COUNT(DISTINCT) 去重计数
聚合与窗口函数54 条

COUNT(DISTINCT) 去重计数

统计去重后的个数,例如独立用户数;NULL 不参与计数,MySQL 还支持多列组合去重。

SQL 速查数据更新于 2026-10-13

COUNT DISTINCT 是什么

COUNT(DISTINCT col) 统计去重后的个数,典型用途是算独立用户数、独立访问数。NULL 不参与计数,多个 NULL 会被忽略。MySQL 额外支持 COUNT(DISTINCT a, b) 这种多列组合去重计数,等价于按组合去重后再计数。去重计数需要在内部维护去重结构,内存与 CPU 开销都高于普通计数,在基数很高的列上尤其明显,报表里要留意这类字段的统计成本。

基本信息

作用统计去重后的非 NULL 值个数
NULL 处理忽略 NULL,不参与计数
多列支持MySQL 支持 COUNT(DISTINCT a, b),PostgreSQL 需改写
开销高于普通计数,需要维护去重结构
近似方案PostgreSQL 可用 hyperloglog 扩展做近似去重统计
适用平台单列形式是标准写法,两库都支持

典型使用场景

  • 独立用户数:日活、月活的去重口径
  • 独立 IP 数:访问来源统计
  • 去重订单数:同一用户的多笔合并成一次
  • 数据基数评估:为索引设计提供选择性参考
  • 组合唯一性检查:对照 COUNT(DISTINCT a, b) 与总行数找重复
  • 报表去重口径:同一口径在多张报表里保持一致

示例

示例
SELECT COUNT(DISTINCT user_id) AS uv,     # 独立用户数
       COUNT(*)                AS pv      # 总访问量
FROM visits
WHERE stat_date = '2024-05-01';

-- MySQL:多列组合去重
SELECT COUNT(DISTINCT user_id, product_id) FROM cart;

-- PostgreSQL:先组合去重再计数
SELECT COUNT(*) FROM (SELECT DISTINCT user_id, product_id FROM cart) t;

相关计数对照

写法统计对象无数据时
COUNT(*)所有行0
COUNT(col)col 非 NULL 的行0
COUNT(DISTINCT col)col 去重后的非 NULL 值0
SUM(col)数值列合计NULL
AVG(col)数值列平均NULL
去重计数忽略 NULL:如果业务上要把「未登录用户」也算一个类别,需要单独统计或用 COALESCE 把 NULL 归类后再计数。
MySQL 早期版本对 COUNT(DISTINCT) 与 GROUP BY 一起用有限制,复杂场景可先用子查询去重再计数,写法更通用。
高基数列上的去重计数会消耗较多内存,报表周期性统计建议落到汇总表,别在每次请求里实时算。
去重口径要在多张报表间保持一致:独立用户数一个按注册口径、一个按下单口径,对账时必然对不上,口径统一写进指标定义。

易错点

  • 把 COUNT(DISTINCT col) 写成 COUNT(col),有重复值时结果偏大
  • 以为 COUNT(DISTINCT) 会把 NULL 算作一个值,实际被完全忽略
  • 在高基数列上频繁实时去重计数,查询内存与耗时都明显上升
  • MySQL 的多列去重计数写法直接搬到 PostgreSQL 报错,需要改写成子查询去重
  • 去重口径在不同报表里不一致,独立用户数与明细行数对不上

数据来源与参考

  • MySQL 8.0 Reference Manual · COUNT DISTINCT
  • PostgreSQL Documentation · Aggregate Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌