COUNT(DISTINCT column) 是统计每组不重复值的唯一靠谱写法,需配合 GROUP BY 使用,主流数据库原生支持,语义清晰且性能更优;注意 NULL 处理、版本兼容性及多列去重限制。

COUNT(DISTINCT column) 是唯一靠谱的写法
想在 GROUP BY 后统计每组里某个字段有多少不重复值,直接套 COUNT(DISTINCT column) 就行。别绕弯写子查询或临时表——多数主流数据库(PostgreSQL、MySQL 5.7+、SQL Server 2017+、Oracle)都原生支持,语义清晰,执行计划也通常更优。
常见错误是先 GROUP BY 再对结果集去重,比如用 SELECT COUNT(*) FROM (SELECT DISTINCT ... GROUP BY ...),这会丢失原始分组上下文,或者根本语法报错。
-
COUNT(DISTINCT column)必须和GROUP BY配合使用,不能单独出现在无分组的 SELECT 中(否则意义不明) - 如果
column允许 NULL,DISTINCT会把所有 NULL 当作一个值处理,即最多计 1 次 - MySQL 5.6 及更早版本不支持
COUNT(DISTINCT)与GROUP BY混用,会报错Invalid use of group function
多列去重计数:括号里写逗号分隔的列名
要统计“用户ID + 操作类型”组合在每组里的不重复次数,就得写 COUNT(DISTINCT user_id, action_type)。注意不是 COUNT(DISTINCT (user_id, action_type))——括号不是函数调用语法,而是列列表分隔符。
这个写法在 PostgreSQL 和 MySQL 8.0+ 支持;但 SQLite 和 SQL Server 不支持多列 DISTINCT,强行写会报错 near "DISTINCT": syntax error 或 Incorrect syntax near ','。
- 替代方案(兼容性更强):
COUNT(DISTINCT CONCAT(user_id, '|', action_type)),但要注意分隔符不能出现在原始数据中,否则会误合并 - PostgreSQL 还可改用
COUNT(DISTINCT ROW(user_id, action_type)),语义更严谨,且能正确处理 NULL - 性能上,多列
DISTINCT通常比字符串拼接快,尤其数据量大时
NULL 值导致计数为 0?检查字段是否真为空
有时明明看到某组有数据,COUNT(DISTINCT column) 却返回 0。大概率不是函数失效,而是该组内 column 全为 NULL ——因为 DISTINCT 对 NULL 的聚合行为是“视为单一值但不计入计数”,等价于 COUNT 忽略 NULL。
验证方法很简单:SELECT COUNT(*), COUNT(column), COUNT(DISTINCT column) FROM t GROUP BY group_col;。如果 COUNT(column) 为 0,那 COUNT(DISTINCT column) 必然也是 0。
- 想把 NULL 当作一个有效取值参与去重计数,得先转换:
COUNT(DISTINCT COALESCE(column, 'NULL_PLACEHOLDER')) - MySQL 中
COALESCE返回值类型需与原字段兼容,否则隐式转换可能引发截断或告警 - 别用
ISNULL()或NVL()替代COALESCE(),跨数据库迁移时容易出错
性能卡在 DISTINCT 上?先看执行计划再优化
COUNT(DISTINCT) 在大数据量分组场景下容易变慢,本质是每个分组都要做一次哈希去重或排序。瓶颈不在 SQL 写法,而在是否命中索引、内存是否够用、以及分组基数是否过高。
用 EXPLAIN(MySQL/PostgreSQL)或 EXECUTION PLAN(SQL Server)看实际执行路径:如果出现 Using temporary; Using filesort 或 Hash Aggregate 且 Input Rows 极大,说明正在磁盘落临时文件。
- 加复合索引能缓解:比如
GROUP BY category+COUNT(DISTINCT user_id),建索引ON table (category, user_id) - PostgreSQL 可尝试
APPROX_COUNT_DISTINCT()获得近似结果,误差率约 2%,速度提升明显 - MySQL 8.0+ 支持直方图统计,对高基数列开启后,优化器可能选择更优的执行路径
EXPLAIN 和小样本验证。

















