广州总部电话:020-85564311
广州总部电话:020-85564311
20年
互联网应用服务商
请输入搜索关键词
知识库 知识库

优网知识库

探索行业前沿,共享知识宝库

MySQL 中的 distinct 和 group by 哪个效率更高?太刁钻了吧!

发布日期:2025-08-21 17:51:26 浏览次数: 809 来源:ITPUB
推荐语
MySQL面试必问的刁钻问题:DISTINCT和GROUP BY到底谁更快?本文用实战案例帮你彻底搞懂两者的性能差异。

核心内容:
1. 索引场景下两者的效率对比
2. 无索引时DISTINCT的性能优势分析
3. GROUP BY隐藏的排序陷阱与解决方案
小优 网站建设顾问
专业来源于二十年的积累,用心让我们做到更好!

这个问题其实比很多人以为的要复杂得多,特别是面试时面试官带着“刁钻”目的来问的时候。如果你直接回一句“效率差不多”可能还真就挂了。咱们今天就来掰扯清楚:MySQL 里的 DISTINCT 和 GROUP BY,到底谁更高效,什么场景下各自更合适,以及你该怎么选。

先抛个结论出来——

在有索引并语义等价的情况下,两者几乎效率一样;但在无索引时,DISTINCT 很可能更快,GROUP BY 会拖后腿,主要是那个“filesort”惹的祸。不过光说这些还不够,你得知道为什么。

我自己在项目里就遇到过类似的情况,那时候是为了清洗数据表里的重复记录,用 GROUP BY 总感觉慢得要死,一换成 DISTINCT,结果就飞了,跑得比我早上打卡还快。

DISTINCT:不动声色地去重

我们先看 DISTINCT。这玩意儿其实逻辑挺简单:你查出来的所有列,只要整行完全一样,就认为是重复的,只保留一条。常规用法是这样:

SELECT DISTINCT age FROM student;

注意,它对你 SELECT 出来的所有字段生效,不是某个字段,而是组合后的整个“行”维度。

比如你写了:

SELECT DISTINCT sex, age FROM student;

它会认为 (male, 10) 和 (female, 10) 是不一样的,只有相同的性别 + 年龄才算重复。

性能层面来说,DISTINCT 做的是“去重”,但如果你给它一个合适的索引,比如 sex, age 的联合索引,它其实不用全表扫描,而是可以直接走索引。MySQL 执行计划里你会看到一个“Using index for group-by”的提示,虽然字面写的是 group-by,但确实也能用于 DISTINCT,这有点迷惑初学者。

GROUP BY:看似一样,实则有坑

再看 GROUP BY。你可能觉得和 DISTINCT 类似,确实在某些简单场景下是一样的,但它本质上是“分组”,然后你可以对每组做聚合。

比如:

SELECT age FROM student GROUP BY age;

这时候看起来和 DISTINCT age 差不多,都是返回不同的年龄值。

但你换成这样:

SELECT sex, age FROM student GROUP BY sex;

MySQL 会返回每个性别的第一条记录的 age,不同的引擎实现可能会选不同的 age,你不能指望它总是按你想的来。所以这个用法在逻辑上和 DISTINCT 就不等价了,结果可能不同。

而更要命的是——在 MySQL 8.0 以前,GROUP BY 是默认会排序的。也就是说哪怕你没写 ORDER BY,它也偷偷给你搞个排序。如果你选的字段没索引覆盖,MySQL 可能就得生成临时表 + filesort,这个组合就是性能黑洞:

Using temporary; Using filesort

看见这两个词,基本可以判断执行效率不会太好,特别是数据量上来了以后,能慢到你怀疑人生。

MySQL 8.0 的“优化”背锅

MySQL 8.0 改了这个默认行为,不再默认隐式排序。这本来是件好事,但也带来一个副作用:一些之前依赖这个排序特性的代码,升级后结果顺序可能变了。所以如果你用了 GROUP BY 想靠它排序,最好老老实实加上 ORDER BY

顺便说句,老版本 MySQL 想避免隐式排序,可以在 GROUP BY 后加 ORDER BY NULL,这是老派 DBA 常用的骚操作。到了 MySQL 8.0,这步就不需要了。

有索引 vs 无索引:才是关键分水岭

你可能发现了,我们上面讲的这些,性能好坏其实并不是 DISTINCT 和 GROUP BY 本身的锅,而是跟有没有用到索引强相关。

如果你用的是 DISTINCT age,而 age 刚好有个索引,那这个 SQL 可能直接走索引,连表都不用扫,效率当然高。

但如果你用了 GROUP BY age,age 没索引,MySQL 就得扫全表、创建临时表、排序,然后再分组,整个流程就重了很多。

也就是说,在“无索引”的前提下:

  • DISTINCT 去重操作,偏“纯”,只需要判断相同行是否重复
  • GROUP BY 是先分组再聚合,如果没有聚合函数,还会默认排序,开销更大

在有索引时,两者都会用上 index,最终执行计划基本相同,所以几乎没有差异。

我个人怎么选?

老实说,我更倾向用 GROUP BY。不是因为它快,而是它更灵活。你别看它一开始像是去重,其实真正的杀手锏是——你可以挂聚合函数上去。

比如:

SELECT age, COUNT(*) FROM student GROUP BY age;

一下就能知道每个年龄段有多少人,这是 DISTINCT 做不到的。

而且 GROUP BY + HAVING 可以让你对分组之后的结果再过滤,比如:

SELECT age, COUNT(*) as c FROM student GROUP BY age HAVING c > 1;

这比你用 DISTINCT 然后自己去计数、再筛选,简单太多了。

当然,如果你只是为了去重,又没啥其他操作,那 DISTINCT 就挺合适,代码也更直观些,尤其是你不打算扩展逻辑的场景。

写代码别光看“表面效率”

面试官要你比较效率,其实不是让你死记硬背谁更快,而是想看你是否知道“为什么更快”。也就是说,你得看得出:

  • 哪种写法在什么版本的 MySQL 上可能走 filesort
  • 你写的字段有没有索引
  • 查询是不是还能加聚合、筛选

我自己在处理大数据量的时候,踩过无数次 “GROUP BY filesort” 的坑,后来一看到 Using temporary; Using filesort 就条件反射去加索引或者改写逻辑了。

另外顺便提一句,DISTINCT 也不是没坑,它的“全字段作用”有时候会意外拉高去重复杂度。比如:

SELECT DISTINCT name, create_time FROM user;

如果 create_time 是毫秒级时间戳,几乎每条记录都不同,根本去不掉重复,结果集和原始数据几乎一样,效率反而更低。用 GROUP BY name + 聚合反倒更合适。

所以啊,这个问题的答案不是 “谁更快”,而是“你知道他们本质上是啥、执行计划差在哪、什么时候该用谁”。

别一上来就丢个“DISTINCT 更快”,面试官可能马上反问你“那聚合怎么算?”

你要做的是,先判断语义是不是完全一样,然后看数据量、索引、版本,再决定用哪个。顺便加上一句“我个人更喜欢用 GROUP BY,因为它更灵活”,就妥了。

优网科技,优秀企业首选的互联网供应服务商

优网科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!

优网科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。优网科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、微信小程序定制开发、移动端应用(手机站APP开发)、微信定制开发(微信官网、微信商城、企业微信)等一系列互联网应用服务。


我要投稿

姓名

文章链接

提交即表示你已阅读并同意《个人信息保护声明》

专属顾问 专属顾问
扫码咨询您的优网专属顾问!
专属顾问
马上咨询
联系专属顾问
联系专属顾问
联系专属顾问
扫一扫马上咨询
扫一扫马上咨询

扫一扫马上咨询

和我们在线交谈!