MySQL優(yōu)化子查詢的實(shí)現(xiàn)示例
大家好,我是小米,一個31歲還在互聯(lián)網(wǎng)“搬磚”路上摸爬滾打的開發(fā)者。今天來和大家聊聊我最近經(jīng)歷的一場面試,主題是 “MySQL子查詢優(yōu)化”。
說實(shí)話,這題目我一聽見,心里咯噔了一下。因?yàn)樽硬樵冞@東西,面試官一問,八成就是在等你掉坑。好在我這些年踩過的坑夠多,順手還能給大家寫篇文章分享一下。
所以今天這篇文章,不僅僅是 面試題解析,更是 實(shí)戰(zhàn)踩坑經(jīng)驗(yàn)總結(jié)。如果你也正在準(zhǔn)備社招面試,或者線上系統(tǒng)里SQL跑得慢得要死,這篇文章一定對你有幫助。
故事開場:面試官的“刁難”
面試官盯著我笑了一下,開口第一句就是:
“你覺得MySQL子查詢該怎么優(yōu)化?”
我腦子里立刻閃回起以前因?yàn)樽硬樵儗懙貌划?dāng),把線上數(shù)據(jù)庫搞成蝸牛的場景。那次領(lǐng)導(dǎo)狠狠批評了我一句:
“小米啊,你這是在寫SQL,還是在給數(shù)據(jù)庫挖墳?”
我心里那個羞愧??!后來我硬生生啃了幾本MySQL優(yōu)化的書,還在項(xiàng)目里做了好幾次實(shí)戰(zhàn)才算明白。
于是,我對面試官微微一笑:“子查詢優(yōu)化啊,我能聊一整天,要聽完整版嗎?”
為什么子查詢經(jīng)常會慢?
在進(jìn)入優(yōu)化方案之前,我們得先搞清楚: 子查詢?yōu)槭裁慈菀淄峡逍阅埽?/strong>
常見問題有三:
1、嵌套太深
- 內(nèi)層子查詢每次都要重新執(zhí)行,數(shù)據(jù)量一大,效率直線下降。
- 特別是 WHERE id IN (SELECT …) 這種寫法,如果子查詢沒索引,簡直噩夢。
2、不能充分利用索引
- 子查詢結(jié)果集經(jīng)常需要臨時(shí)表存放,而臨時(shí)表往往沒有合適的索引。
3、文件排序 & 臨時(shí)表開銷大
- 一旦涉及 GROUP BY、DISTINCT、ORDER BY,MySQL可能會開臨時(shí)表甚至文件排序,速度嗖嗖掉。
這就是為什么子查詢看起來優(yōu)雅簡潔,但實(shí)際經(jīng)常跑得像蝸牛。
優(yōu)化方法一:用關(guān)聯(lián)查詢替代子查詢
面試官最想聽到的第一個答案就是這個:
“能不用子查詢,就用JOIN代替。”
來看一個例子。
低效子查詢寫法:

這里的問題是:內(nèi)層子查詢可能會重復(fù)執(zhí)行,效率低下。
改成關(guān)聯(lián)查詢:

這樣做的好處:
- 避免重復(fù)掃描:JOIN會直接利用索引做匹配。
- 優(yōu)化器更聰明:JOIN查詢可以用到更優(yōu)的執(zhí)行計(jì)劃,比如索引合并、驅(qū)動表選擇等。
- 結(jié)果集更可控:方便加條件、加排序,而不是靠子查詢臨時(shí)表。
面試小技巧:當(dāng)面試官追問時(shí),你可以補(bǔ)充一句:
“如果student.id是主鍵,JOIN的效率會比IN快很多,尤其是大表查詢。”
這句話一出口,面試官眼睛一定會亮一下。
優(yōu)化方法二:優(yōu)化GROUP BY和DISTINCT
面試時(shí),面試官繼續(xù)追問我:
“那GROUP BY和DISTINCT呢?它們是不是也會拖慢速度?”
我立刻想到了之前的慘痛經(jīng)歷。那時(shí)候我寫了一個統(tǒng)計(jì)SQL:

結(jié)果線上跑了半天,CPU打滿。后來我才知道:
- MySQL執(zhí)行 GROUP BY 時(shí)默認(rèn)會排序。
- 如果數(shù)據(jù)量大,沒索引,那就是災(zāi)難。
優(yōu)化方案:
1、利用索引
- 給 student_id 建索引,MySQL能直接利用索引分組,大幅加速。
2、用DISTINCT時(shí)同理
- SELECT DISTINCT student_id FROM score;
- 如果有索引,DISTINCT直接走索引去重,效率嗖嗖的。
3、GROUP BY + ORDER BY NULL
- 如果你不關(guān)心結(jié)果的順序,可以這樣寫:

- ORDER BY NULL 告訴MySQL:別再排序了,直接分組結(jié)果就行。這樣能避免文件排序,大幅提速。
優(yōu)化方法三:關(guān)聯(lián)查詢中,使用標(biāo)識列分組更高效
假設(shè)我們有學(xué)生表和成績表,需要統(tǒng)計(jì)每個學(xué)生選課數(shù)。
原始寫法:

這里用 s.name 分組其實(shí)很低效,因?yàn)?name 不是主鍵,還可能存在重復(fù)或者長字符串比較。
優(yōu)化寫法:

理由很簡單:
- 主鍵/標(biāo)識列更容易利用索引。
- 字符串分組開銷大,而數(shù)字分組快如閃電。
小米碎碎念:這一點(diǎn),面試官經(jīng)常會用來考察候選人是否理解“索引對分組的影響”。
優(yōu)化方法四:WITH ROLLUP要慎用
有些小伙伴喜歡用 WITH ROLLUP 做超級聚合,比如統(tǒng)計(jì)成績時(shí)自動加總:

雖然語法很酷,但問題是:
- ROLLUP 計(jì)算量大,容易讓查詢變慢。
- 有些邏輯其實(shí)在應(yīng)用層做更靈活,比如用Java/Go/Python聚合。
所以,面試官要是問到這里,我一般會說:
“在數(shù)據(jù)量不大時(shí),ROLLUP很方便。但如果是大數(shù)據(jù)量場景,建議把超級聚合邏輯挪到應(yīng)用程序處理,數(shù)據(jù)庫只負(fù)責(zé)最基本的統(tǒng)計(jì)。”
這句話能讓你顯得思路全面,不死摳SQL,而是懂得架構(gòu)層面取舍。
實(shí)戰(zhàn)經(jīng)驗(yàn):子查詢優(yōu)化的黃金四步
我總結(jié)了一套面試時(shí)特別好用的“四步口訣”,分享給大家:
- 能JOIN就不用子查詢:特別是 IN (SELECT …),替換成JOIN幾乎必快。
- GROUP BY/DISTINCT走索引:一定要確認(rèn)字段有索引,不然就是全表掃描。
- 分組列優(yōu)先用主鍵或整型標(biāo)識列:避免用字符串或復(fù)雜字段做分組。
- ORDER BY NULL + 應(yīng)用層聚合:不需要排序時(shí),果斷加 ORDER BY NULL;超級聚合挪到應(yīng)用層。
只要這四步背下來,面試官再怎么追問,你都能侃侃而談。
小米的踩坑瞬間
最后分享一個讓我刻骨銘心的場景。那是我入職某電商平臺的第一周,老板讓我寫個統(tǒng)計(jì)SQL:

結(jié)果跑了10分鐘還沒出來,老板差點(diǎn)以為我不會寫SQL。后來我改成:

0.8秒出結(jié)果!老板看完還夸我一句:“小米,干得漂亮。”
從那以后,我就徹底記住了:
子查詢能不用就別用,優(yōu)化就是錢。”
結(jié)語
如果你在面試中被問到“如何優(yōu)化子查詢?”,千萬別慌。按照我上面分享的思路來:
- 先說子查詢的缺點(diǎn)(執(zhí)行慢、索引利用率低、容易臨時(shí)表)。
- 再一條條拋出優(yōu)化思路(JOIN替代、GROUP BY優(yōu)化、標(biāo)識列分組、ORDER BY NULL、ROLLUP挪應(yīng)用層)。
- 最后補(bǔ)充一點(diǎn)自己的實(shí)戰(zhàn)經(jīng)驗(yàn)。
這樣下來,不僅能顯得你技術(shù)扎實(shí),還能讓面試官覺得你是“踩過坑、能解決問題”的人。
畢竟,面試官要找的不是會背八股的人,而是能把問題搞定的工程師。
END
到此這篇關(guān)于MySQL優(yōu)化子查詢的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)MySQL優(yōu)化子查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySql .frm數(shù)據(jù)庫文件導(dǎo)入的問題
手頭有.frm 文件,怎樣導(dǎo)入數(shù)據(jù)庫???2009-07-07
MySQL數(shù)據(jù)庫線上修改表結(jié)構(gòu)的方法
MySQL有一個把鎖,叫做MDL元數(shù)據(jù)鎖,當(dāng)對表修改的時(shí)候,會自動給表加上這把鎖,也就是不需要自己顯式使用,這篇文章主要介紹了MySQL數(shù)據(jù)庫線上修改表結(jié)構(gòu)的方法,需要的朋友可以參考下2022-09-09
mysql給id設(shè)置默認(rèn)值為UUID的實(shí)現(xiàn)方法
由于mysql并不支持默認(rèn)值為函數(shù)類型,給id設(shè)值有兩種方式,本文主要介紹了mysql給id設(shè)置默認(rèn)值為UUID的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08
解決Navicat for Mysql連接報(bào)錯1251的問題(連接失敗)
記得在之前給大家介紹過Navicat for Mysql連接報(bào)錯的問題,可能寫的不夠詳細(xì),今天在稍作修改補(bǔ)充下,對Navicat for Mysql連接報(bào)錯1251問題感興趣的朋友跟隨小編一起看看吧2021-05-05
詳解記錄MySQL中l(wèi)ower_case_table_names的坑
這篇文章主要介紹了詳解記錄MySQL中l(wèi)ower_case_table_names的坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
一步步教你利用Mysql存儲過程造百萬級數(shù)據(jù)
因工作需要維護(hù)一張中建表數(shù)據(jù)內(nèi)置,所以得造數(shù)據(jù)所以使用存儲過程來造數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于如何一步步利用Mysql存儲過程造百萬級數(shù)據(jù)的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
Mysql運(yùn)行環(huán)境優(yōu)化(Linux系統(tǒng))
這篇文章主要介紹了Mysql運(yùn)行環(huán)境優(yōu)化(Linux系統(tǒng)),本文優(yōu)化了修改Linux默認(rèn)的IO調(diào)度算法、擴(kuò)大文件描述符、禁用numa特性、修改swappiness設(shè)置、優(yōu)化文件系統(tǒng)掛載參數(shù)等配置,需要的朋友可以參考下2015-02-02

