COUNT(DISTINCT col1, col2) 统计的是(col1,col2)唯一组合数,并非单列去重之和;其性能差、不支持并行,建议用GROUP BY子查询替代。

MySQL中COUNT(DISTINCT col1, col2)根本没失效,只是语义被误解了
很多人说“失效”,其实是误以为它等价于“分别对每列去重后计数”,比如以为 COUNT(DISTINCT a, b) 会返回 COUNT(DISTINCT a) + COUNT(DISTINCT b) —— 这完全错误。MySQL 的 COUNT(DISTINCT col1, col2) 实际统计的是「唯一组合」的数量,即把 (col1, col2) 当作一个复合元组去重后计数。
常见错误现象:结果比预期小,且不等于单列去重之和
例如表中有:
a | b --|-- 1 | x 1 | y 2 | x 2 | x
执行 COUNT(DISTINCT a, b) 得到 3(组合 (1,x)、(1,y)、(2,x)),而 COUNT(DISTINCT a) 是 2,COUNT(DISTINCT b) 是 2,加起来是 4 —— 两者不可比。
- 这不是 bug,是标准 SQL 行为(MySQL 8.0+ 和 PostgreSQL/SQL Server 均一致)
- 如果想实现“各列独立去重再求和”,必须显式写成:
COUNT(DISTINCT a) + COUNT(DISTINCT b) - 若想统计“任意一列不同就算不同”,需用
UNION拆开再聚合,但性能差、逻辑重,一般不推荐
COUNT(DISTINCT) 多列在大表上性能极差,容易卡住
MySQL 对多列 DISTINCT 无法有效利用复合索引做覆盖扫描,内部通常要构建临时哈希表或排序,内存压力大,还可能触发磁盘临时表(Created_tmp_disk_tables 上升)。
- 确认是否真需要多列组合去重:很多业务场景其实只要
GROUP BY a, b后再计数,更可控 - 避免在
WHERE条件弱、无索引的列上用COUNT(DISTINCT a, b),响应时间可能从毫秒级跳到秒级甚至超时 - 5.7 中该操作不支持并行;8.0 仍不支持并行 DISTINCT,别指望加核提速
替代方案:用 GROUP BY + 子查询更清晰、更易优化
当逻辑复杂或需兼容旧版本时,显式 GROUP BY 更可靠:
SELECT COUNT(*) FROM ( SELECT a, b FROM t GROUP BY a, b ) AS _tmp;
这样写的好处:
- 可明确加
WHERE过滤后再分组,避免全表扫 - 能利用
(a, b)复合索引加速GROUP BY(前提是索引顺序匹配) - 便于加
LIMIT调试中间结果,而COUNT(DISTINCT)无法调试中间状态 - 在某些 OLAP 场景下,配合物化视图或汇总表效果更好
实际使用时,最常被忽略的是:组合去重的语义和性能代价是一体两面——你以为只改了个函数名,其实底层执行计划已完全不同。


















