Join查詢再熟悉不過了,看視沒有必要把它拿出來說事,但某天一個學生問起了一個問題,有必要拿來說下。
很多同學的畢生夢想都是想進BATJ的某家公司,其中又以案例爲多數,是的,不管從哪個角度來說,阿里都是一個非常棒的公司,值得去挑戰一把。
回到今天的話題,一個同學(阿里的鐵桿粉),問了我一個問題,在實際工作中到底應不應該用join查詢,到底應該注意點什麼?
別以爲這個問題很傻,如果你關注過阿里的規範,裏面就有顯著的一條:
【強制】超過三個表禁止 join。需要 join 的字段,數據類型必須絕對一致;多表關聯查詢時,保證被關聯的字段需要有索引。
首先,我要交代,上面這句話出自《阿里java編程規範手冊》,並不是我的原創,另外我想說的是,對於上面這句話,我不管你懂不懂爲什麼,請按手冊裏面說的,強制去執行。
不過既然有同學再問,我認爲還是有必要把這個問題拿來分析下。
禁止超過3表的JOIN
如果太多的表JOIN對性能的影響是非常大的(Join的性能以及注意事項我後面再分析),這個我相信,對於絕大多數讀者來說都是認可的,起碼能做到表面上理解,但也不排除某些另外情況,比如說…
某天,有個同學小甲,給我發個SQL語句,一方面誇誇其談它對公司的業務,表結構瞭解的如何透徹。
我打開sql文件後,一個2132行的sqL語句映入眼簾,我心裏頓時(&%%¥&……),好吧,我得承認這情況並不只一個,而且他們以這個爲榮,我不知道當這同學離職後,後面接手的會不會和我一樣的心情。
現在我也無力反駁他,這可能在某些特殊的情況下對他是好的(誰敢開除他,誰敢接他的手),我現在只想聊聊出現過多表關聯之後怎麼來解決。
確實答案也出自《阿里java編程規範手冊》
【推薦】字段允許適當冗餘,以提高查詢性能,但必須考慮數據一致。
其實雖然規範裏面沒說,但這是數據庫設計裏面非常重要的一條:
反範式設計
· 反範式化是針對範式化而言的,在前面介紹了數據庫設計的範式
· 所謂得反範式化就是爲了性能和讀取效率得考慮而適當得對數據庫設計範式得要求進行違反
· 允許存在少量的冗餘,換句話來說反範式化就是使用空間來換取時間
舉一個簡單的例子:
上面這個sql語句查詢的數據來自a,b兩張表,仔細看你會發現,其中只有cl4這一列是出自b表,其他的所有都是a表,這樣可以考慮建立一個c表,把c1l,cl2,cl3,cl4的數據全部關聯起來,實際做的事情就是冗餘了cl4這個字段。
帶來的好處呢? 查詢的時候只要查詢c表,效率不會提升纔怪。
數據類型必須一致
數據類型必須一致,請完全遵守,如果你定是要尋根究底轉牛角尖,那我們做個實驗,做實驗的前提是你要了解些許的執行計劃,當然對索引也得一知半解才行。
數據和表都準備好了後,我來寫一個sql語句:
很棒,結果也查詢出來了,name是varchar類型, 而給出的2000是整型,這有什麼問題嗎?結果不是正確的嘛?
彆着急,還記得前面創建了索引嘛?
使用執行計劃看下:
看出問題了嗎?雖然我指定的name上面是索引的,但數據類型不一致,不好意思,結果是全表掃描。
如果數據類型一致呢?
key有值,代表就是用到了索引,so,不需要再鑽牛角尖了吧!
保證被關聯的字段需要有索引
這句話很好理解吧,如果t1,t2表,如sql語句:
你可能會問straight_join是什麼? 他和join有什麼區別呢?
好吧,你既然問到了,我就還是說下,如果你使用join,Mysql優化器可能會選擇t1或者t2來作爲驅動表,而我使用的是straight_join,那麼關係很明確了,t1是驅動表,那t2就是被驅動表。
既然語句知道被驅動表了,那被關聯的字段就是t2.a,按照規範的要求,必須在t2表的a列上必須創建有索引。
t1是驅動表,我從t1表裏面取出數據後,再去t2表查詢:
· 如果t2.a有索引,我根據索引查詢就好,查詢了結果合併t1表的記錄返回。
· 如果t2.a沒索引,那麼就尷尬了,需對t1表裏面的所有數據都需要在t2表進行一次全表掃描,如果t1是1000行數據,t2是10000,那得掃描多少行呢?結果是(t1行數*t2行數)1000萬。
這個時候我相信你也已經理解爲什麼被關聯的字段需要有索引了吧。