为什么SQL查询中用COUNT(DISTINCT)去重计数性能那么糟糕?
- 内容介绍
- 相关推荐
本文共计649个文字,预计阅读时间需要3分钟。
基本原因在于执行路径的不同:
子查询写法必须满足的三个前提条件
不是所有 SELECT COUNT(*) FROM (SELECT DISTINCT ...) 都快,它只在以下情况真正生效:
- WHERE 条件足够强,能大幅减少输入行数(比如
dt >= '2026-04-15',而不是status IN ('a','b','c')这种低选择率条件) - 去重字段
col有单列索引或作为联合索引最左前缀(否则子查询仍要全表扫) - 子查询结果集行数远小于原始表(理想是 COUNT(*) 反而多一次遍历
MySQL中容易被忽略的索引陷阱
即使你给 user_id 加了索引,COUNT(DISTINCT user_id) 仍可能不走索引——因为 MySQL 优化器发现去重逻辑无法跳过 NULL 值判断或需要回表取其他字段时,会主动放弃索引扫描。
本文共计649个文字,预计阅读时间需要3分钟。
基本原因在于执行路径的不同:
子查询写法必须满足的三个前提条件
不是所有 SELECT COUNT(*) FROM (SELECT DISTINCT ...) 都快,它只在以下情况真正生效:
- WHERE 条件足够强,能大幅减少输入行数(比如
dt >= '2026-04-15',而不是status IN ('a','b','c')这种低选择率条件) - 去重字段
col有单列索引或作为联合索引最左前缀(否则子查询仍要全表扫) - 子查询结果集行数远小于原始表(理想是 COUNT(*) 反而多一次遍历
MySQL中容易被忽略的索引陷阱
即使你给 user_id 加了索引,COUNT(DISTINCT user_id) 仍可能不走索引——因为 MySQL 优化器发现去重逻辑无法跳过 NULL 值判断或需要回表取其他字段时,会主动放弃索引扫描。

