distinct是专为去重设计的语义操作,group by本质用于分组聚合;仅需去重时,distinct逻辑更轻、优化路径更直接,无索引时group by可能多触发using filesort。

MySQL 中 DISTINCT 和 GROUP BY 去重,本质不是“谁更快”,而是“谁更贴合语义”
直接说结论:DISTINCT 是专为去重设计的语义操作,GROUP BY 是为分组聚合设计的;当仅需去重、不带聚合时,DISTINCT 逻辑更轻、优化路径更直接。强行用 GROUP BY 实现纯去重,MySQL 有可能多走一步排序(Using filesort),尤其在无索引列上。
DISTINCT 的执行路径:哈希去重 or 索引扫描,不默认排序
MySQL 对 DISTINCT 的常见实现方式有两种:
- 小结果集:构建内存哈希表,逐行插入并去重,最后输出;
- 有覆盖索引时:直接走
Using index for group-by(注意名字里有 group-by,但实际是优化器复用路径,并不真做分组); - 不强制对结果排序,除非你显式加了
ORDER BY;
例如:SELECT DISTINCT city FROM users; 如果 city 有索引,Explain 显示 type: index + Extra: Using index,基本就是索引扫描一遍完事。
GROUP BY 的执行路径:分组 → 排序(可能)→ 取首行
即使你只写 SELECT city FROM users GROUP BY city;,MySQL 内部仍按分组逻辑处理:
- 若
city无索引:先建临时表,再对分组键排序(触发Using filesort),然后每组取第一行; - 若
city有索引且是前导列:可走松散/紧凑索引扫描,跳过排序,效率接近DISTINCT; - 一旦语句里出现非分组列(如
SELECT city, name FROM users GROUP BY city),MySQL 5.7+ 默认报错(sql_mode=only_full_group_by),必须用聚合函数或明确指定取值逻辑;
所以,GROUP BY 在纯去重场景下,多一层语义负担和潜在排序开销。
什么时候 GROUP BY 反而更优?别被“去重”二字带偏
真正影响选择的不是“哪个快”,而是你要不要后续扩展能力:
- 需要统计每个城市的用户数?必须用
GROUP BY city COUNT(*),DISTINCT不支持聚合; - 要去重后过滤分组(比如只保留出现次数 ≥ 5 的城市)?只能用
HAVING,DISTINCT没这功能; - 要联合多列去重,且其中一列有高基数索引(如
(status, created_at)),GROUP BY有时能更好利用覆盖索引,避免回表;
简单说:没聚合就用 DISTINCT;要聚合、要 HAVING、要复用已有复合索引结构,就选 GROUP BY —— 效率差异往往藏在索引是否匹配、是否触发 filesort 这些细节里,而不是关键字本身。











