摘要:大家好,我是小米,一个31岁还在互联网“搬砖”路上摸爬滚打的开发者。今天来和大家聊聊我最近经历的一场面试,主题是“MySQL子查询优化”。
大家好,我是小米,一个31岁还在互联网“搬砖”路上摸爬滚打的开发者。今天来和大家聊聊我最近经历的一场面试,主题是 “MySQL子查询优化”。
说实话,这题目我一听见,心里咯噔了一下。因为子查询这东西,面试官一问,八成就是在等你掉坑。好在我这些年踩过的坑够多,顺手还能给大家写篇文章分享一下。
所以今天这篇文章,不仅仅是 面试题解析,更是 实战踩坑经验总结。如果你也正在准备社招面试,或者线上系统里SQL跑得慢得要死,这篇文章一定对你有帮助。
面试官盯着我笑了一下,开口第一句就是:
“你觉得MySQL子查询该怎么优化?”
我脑子里立刻闪回起以前因为子查询写得不当,把线上数据库搞成蜗牛的场景。那次领导狠狠批评了我一句:
“小米啊,你这是在写SQL,还是在给数据库挖坟?”
我心里那个羞愧啊!后来我硬生生啃了几本MySQL优化的书,还在项目里做了好几次实战才算明白。
于是,我对面试官微微一笑:“子查询优化啊,我能聊一整天,要听完整版吗?”
在进入优化方案之前,我们得先搞清楚: 子查询为什么容易拖垮性能?
常见问题有三:
1、嵌套太深
内层子查询每次都要重新执行,数据量一大,效率直线下降。特别是 WHERE id IN (SELECT …) 这种写法,如果子查询没索引,简直噩梦。2、不能充分利用索引
子查询结果集经常需要临时表存放,而临时表往往没有合适的索引。3、文件排序 & 临时表开销大
一旦涉及 GROUP BY、DISTINCT、ORDER BY,MySQL可能会开临时表甚至文件排序,速度嗖嗖掉。这就是为什么子查询看起来优雅简洁,但实际经常跑得像蜗牛。
面试官最想听到的第一个答案就是这个:
“能不用子查询,就用JOIN代替。”
来看一个例子。
低效子查询写法:
这里的问题是:内层子查询可能会重复执行,效率低下。
改成关联查询:
这样做的好处:
避免重复扫描:JOIN会直接利用索引做匹配。优化器更聪明:JOIN查询可以用到更优的执行计划,比如索引合并、驱动表选择等。结果集更可控:方便加条件、加排序,而不是靠子查询临时表。面试小技巧:当面试官追问时,你可以补充一句:
“如果student.id是主键,JOIN的效率会比IN快很多,尤其是大表查询。”
这句话一出口,面试官眼睛一定会亮一下。
面试时,面试官继续追问我:
“那GROUP BY和DISTINCT呢?它们是不是也会拖慢速度?”
我立刻想到了之前的惨痛经历。那时候我写了一个统计SQL:
结果线上跑了半天,CPU打满。后来我才知道:
MySQL执行 GROUP BY 时默认会排序。如果数据量大,没索引,那就是灾难。优化方案:
1、利用索引
给 student_id 建索引,MySQL能直接利用索引分组,大幅加速。2、用DISTINCT时同理
SELECT DISTINCT student_id FROM score;如果有索引,DISTINCT直接走索引去重,效率嗖嗖的。3、GROUP BY + ORDER BY NULL
如果你不关心结果的顺序,可以这样写:ORDER BY NULL 告诉MySQL:别再排序了,直接分组结果就行。这样能避免文件排序,大幅提速。假设我们有学生表和成绩表,需要统计每个学生选课数。
原始写法:
这里用 s.name 分组其实很低效,因为 name 不是主键,还可能存在重复或者长字符串比较。
优化写法:
理由很简单:
主键/标识列更容易利用索引。字符串分组开销大,而数字分组快如闪电。小米碎碎念:这一点,面试官经常会用来考察候选人是否理解“索引对分组的影响”。
有些小伙伴喜欢用 WITH ROLLUP 做超级聚合,比如统计成绩时自动加总:
虽然语法很酷,但问题是:
ROLLUP 计算量大,容易让查询变慢。有些逻辑其实在应用层做更灵活,比如用Java/Go/Python聚合。所以,面试官要是问到这里,我一般会说:
“在数据量不大时,ROLLUP很方便。但如果是大数据量场景,建议把超级聚合逻辑挪到应用程序处理,数据库只负责最基本的统计。”
这句话能让你显得思路全面,不死抠SQL,而是懂得架构层面取舍。
我总结了一套面试时特别好用的“四步口诀”,分享给大家:
能JOIN就不用子查询:特别是 IN (SELECT …),替换成JOIN几乎必快。GROUP BY/DISTINCT走索引:一定要确认字段有索引,不然就是全表扫描。分组列优先用主键或整型标识列:避免用字符串或复杂字段做分组。ORDER BY NULL + 应用层聚合:不需要排序时,果断加 ORDER BY NULL;超级聚合挪到应用层。只要这四步背下来,面试官再怎么追问,你都能侃侃而谈。
最后分享一个让我刻骨铭心的场景。那是我入职某电商平台的第一周,老板让我写个统计SQL:
结果跑了10分钟还没出来,老板差点以为我不会写SQL。后来我改成:
0.8秒出结果!老板看完还夸我一句:“小米,干得漂亮。”
从那以后,我就彻底记住了:
子查询能不用就别用,优化就是钱。”
如果你在面试中被问到“如何优化子查询?”,千万别慌。按照我上面分享的思路来:
先说子查询的缺点(执行慢、索引利用率低、容易临时表)。再一条条抛出优化思路(JOIN替代、GROUP BY优化、标识列分组、ORDER BY NULL、ROLLUP挪应用层)。最后补充一点自己的实战经验。这样下来,不仅能显得你技术扎实,还能让面试官觉得你是“踩过坑、能解决问题”的人。
毕竟,面试官要找的不是会背八股的人,而是能把问题搞定的工程师。
我是小米,一个还在努力成长的程序员。希望今天这篇文章能帮你在面试里多拿几分,也能在工作中少踩几个坑。
如果你觉得文章有用,记得点个“赞”和“在看”,我们下次再见!
来源:鸿灿教育