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 一起用有限制,复杂场景可先用子查询去重再计数,写法更通用。
高基数列上的去重计数会消耗较多内存,报表周期性统计建议落到汇总表,别在每次请求里实时算。
去重口径要在多张报表间保持一致:独立用户数一个按注册口径、一个按下单口径,对账时必然对不上,口径统一写进指标定义。