DISTINCT在去重字段取值极少(如3–5个值)而数据量极大时通常更快,因其启用内存哈希去重避免排序;GROUP BY在旧版本隐式排序、无索引或单列索引用于多列去重时易触发filesort或磁盘临时表。

MySQL执行DISTINCT比GROUP BY快的典型场景
当去重字段取值种类极少(比如只有3–5个不同值),而表数据量很大(如百万行)时,DISTINCT常比GROUP BY快。这不是语法优势,而是底层算法差异导致的:MySQL对DISTINCT在小基数场景下会启用哈希去重(内存中建 hash 表,边读边判重),避免排序开销;而GROUP BY即使不显式排序,在旧版本或某些执行路径下仍可能触发Using filesort或磁盘临时表。
为什么有索引时两者性能常无差异
单列去重且该列有B+Tree索引时,DISTINCT和GROUP BY很可能走完全相同的执行计划——type: index、Extra: Using index。此时优化器已将二者等价重写,关键看key_len是否匹配索引定义长度、rows是否接近实际扫描行数。别只信EXPLAIN输出里的“Using index”,要结合Handler_read_rnd_next状态变量确认是否真在走索引页顺序读取。
GROUP BY在什么情况下反而更慢
以下情况容易让GROUP BY变慢,而DISTINCT不受影响:
- MySQL 8.0之前版本,未加
ORDER BY NULL时,默认隐式排序,强制Using filesort - ORM(如EF Core)把
.Distinct()翻译成GROUP BY,但字段无索引,执行时默默走全表+磁盘临时表 - 多列去重却只建了单列索引,
GROUP BY a, b无法利用索引顺序,被迫建临时表并排序;而DISTINCT a, b至少还能用哈希去重
真正决定快慢的不是关键字,而是这三件事
你改写SQL前,先确认这三项:
- 去重字段是否有覆盖索引?联合索引
(a, b)对DISTINCT a, b和GROUP BY a, b都有效,单列索引a或b都无效 - 执行时是否真的用了索引?查
SHOW STATUS LIKE 'Handler_read%',Handler_read_rnd_next飙升说明在随机回表 - 业务是否真只需要去重?如果要“每个用户取最新订单”,硬套
GROUP BY user_id返回的order_time大概率不是最大值——得用ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_time DESC)
最常被忽略的是:你以为在比DISTINCT和GROUP BY,其实瓶颈早藏在索引缺失、执行计划误判或业务语义错配里。


















