一文搞懂MySQL的Join
??點(diǎn)擊上方 "程序員小樂" ,關(guān)注公眾號
8點(diǎn)20分,第一時間與你相約
每日英文
A single hand that wipes tears during failures is much better than countless hands that come together to clap on success.?
失敗的時候,一只拭去你淚痕的手,要比成功的時候,無雙只向你祝賀的手重要。
每日掏心話
有的時候你得去在乎的少一些,那么你才是能去看到有沒有人會在乎得多一些。
來自:xcrossed | 責(zé)編:樂樂
鏈接:jianshu.com/p/e07dd9782b42
圖片來自網(wǎng)絡(luò)
往日回顧:線上故障處理深入思考,看這篇就夠了!? ?正文? ?MySQL的Join到底能不能用經(jīng)常聽到2種觀點(diǎn):join性能低,盡量少用多表join時,變?yōu)槎鄠€SQL進(jìn)行多次查詢其實(shí)對于上面的觀點(diǎn)一定程度上是正確的,但不是完全正確。但之所以流傳這么廣,主要還是沒有搞清楚實(shí)際狀態(tài),而根據(jù)實(shí)際使用中總結(jié)出來的一些模糊規(guī)律。只有了解的MySQL的Join實(shí)際執(zhí)行方式,就會知道上面2種觀點(diǎn)是一種模糊的規(guī)律,這種規(guī)律并不能指導(dǎo)我們實(shí)際開發(fā)。下面就說說MySQL的實(shí)際join執(zhí)行方式。MySQL的Join是如何執(zhí)行的join可以說一種集合的運(yùn)算,比如left join,right join,inner join,full join,outer join,cross join等,這些集合間的計算關(guān)系對應(yīng)在高中數(shù)學(xué)集合里面的交集,并集,補(bǔ)集,全集等。但在實(shí)際的代碼中,join運(yùn)算基本上是通過多層循環(huán)來實(shí)現(xiàn)的。舉一個例子,假設(shè)有t1,t2兩張表,表結(jié)構(gòu)分別如下:create?table?t1?(id?int?not?null?AUTO_INCREMENT,username?varchar(20)?not?null?default?'',age?int?not?null?default?0,PRIMARY?key?(`id`))ENGINE=INNODB?DEFAULT?CHARSET=UTF8MB4??;create?table?t2(id?int?not?null?auto_increment,username?varchar(20)?not?null?default?'',score?int?not?null?defalut?0,primary?key?(`id`)))ENGINE=INNODB?DEFAULT?CHARSET=UTF8MB4;假設(shè)t1有100條數(shù)據(jù),t2表有200條數(shù)查詢sql為:select?t1.*,t2.*?from?t1?left?join?t2?on(t1.username=t2.username)那么這條SQL的執(zhí)行步驟如下:從表t1中取一行數(shù)據(jù)r1從r1中,取出字段username到表t2中查詢?nèi)〕霰韙2中滿足條件的行,跟r1組成一行,作為結(jié)果集的一部份重復(fù)執(zhí)行步驟1,2,3,直到表t1的所以數(shù)據(jù)循環(huán)完畢基本上先遍歷t,1,然后根據(jù)t1中的每行數(shù)據(jù)中的username,去表t2中查找滿足條件的記錄。基本就是2層循環(huán)。如何優(yōu)化join查詢從上面可以看出,join本質(zhì)是循環(huán),這里的開銷如下:遍歷t1數(shù)據(jù),讀取數(shù)據(jù)為t1表的行數(shù),假設(shè)行數(shù)為n,則復(fù)雜度也為n根據(jù)t1的匹配字段username去t2中一行一行的查詢數(shù)據(jù)這個過程,因?yàn)镸ySQL的數(shù)據(jù)存儲結(jié)構(gòu)為二叉樹,時間復(fù)雜度為log2(m) m為t2表的總行數(shù)那么總復(fù)雜度近似為 n+n(2log2(m))從上面的步驟可以看出,優(yōu)化方向:降低t1查詢時的開銷,主要是磁盤io開銷,避免全表掃描,用索引降低t2查詢時的開銷,也用索引將數(shù)據(jù)量多的表做被驅(qū)動表,小表作驅(qū)動表,m取了對數(shù),大表數(shù)據(jù)量大對復(fù)雜度的影響沒有線性增長緩存t1表,不用每次去磁盤load,比如一次緩存100條,那么能顯著降低磁盤讀數(shù)據(jù)次數(shù),t2每次與緩存中的t1數(shù)據(jù)進(jìn)行比較隨機(jī)磁盤讀比較耗費(fèi)磁盤性能,轉(zhuǎn)為順序讀,因?yàn)槎鏄涞拇鎯Y(jié)構(gòu),每次非主鍵查找,有一個回表的動作,即根據(jù)主鍵再次查詢需要的數(shù)據(jù)優(yōu)化的基本方法:減少循環(huán)次數(shù),減少磁盤IO次數(shù),變隨機(jī)IO為順序IO其實(shí)MySQL針對上面的優(yōu)化方法有對應(yīng)的算法:Simple Nested Loop Join 最普通的循環(huán),這個要避免Block Nested Loop Join 主要是針對t2表上沒有索引,在步驟2將t2中的每一行數(shù)據(jù)跟join buffer數(shù)據(jù)做對比,這樣將磁盤操作轉(zhuǎn)為內(nèi)存操作進(jìn)行比較,但是如果被驅(qū)動表的數(shù)據(jù)比較大的話,也影響性能,主要是cache pool被占滿,導(dǎo)致MySQL性能下降Index Nested Join 就是都通過主鍵進(jìn)行查找關(guān)聯(lián),這種性能比較好Batched Key Access Join 這個是 Index Nested Join上做的優(yōu)化,因?yàn)榛乇淼拇嬖?#xff0c;隨機(jī)操作io也很耗費(fèi)性能,這個算法的核心在于通過輔助索引去查找時,將得到的主鍵進(jìn)行排序,然后按照主鍵遞增的順序進(jìn)行查找,對磁盤的讀接近順序讀,從而優(yōu)化性能到底要不用Join從上面的分析我們可以看到,用Join還是可行的,只要性能可控且在接受范圍內(nèi),還是能減少代碼復(fù)雜度的。需要避免的是join的表沒有索引,不然這樣的SQL發(fā)線上是災(zāi)難性的。總結(jié)Join還是可以大膽的使用,只要把握好幾個原則:盡量讓join的列是索引列,而且最好是類型相同,盡可能是主鍵索引盡量將小表做驅(qū)動表(這一點(diǎn)MySQL在5.6某個版本后能自動完成)養(yǎng)成將寫好的SQL進(jìn)行explain的好習(xí)慣,觀察SQL的執(zhí)行過程你對MySQL的join的理解?歡迎在留言區(qū)留下你的觀點(diǎn),一起討論提高。如果今天的文章讓你有新的啟發(fā),學(xué)習(xí)能力的提升上有新的認(rèn)識,歡迎轉(zhuǎn)發(fā)分享給更多人。歡迎各位讀者加入程序員小樂技術(shù)群,在公眾號后臺回復(fù)“在網(wǎng)站上添加加入QQ群的按鈕 加群按鈕 網(wǎng)站加群按鈕 添加加群按鈕 QQ群按鈕”或者“學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)學(xué)習(xí)”即可。
猜你還想看
阿里、騰訊、百度、華為、京東、搜狗和滴滴最新面試題匯集
10張 GIF 動圖讓你弄懂遞歸等概念
切換到Linux工作,世界更美好
阿里HR的10條求職黃金定律,進(jìn)大廠不可錯過!
史上最爛的項目:苦撐 12 年,600 多萬行代碼史上最爛項目:苦撐12年,600多萬行代碼...聊一聊秒殺架構(gòu)設(shè)計
關(guān)注「程序員小樂」,收看更多精彩內(nèi)容總結(jié)
以上是生活随笔為你收集整理的一文搞懂MySQL的Join的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 修炼手册】常用技术篇
- 下一篇: 怎样在sqlite3上执行SQL语句