- 一:為什么做這種限制?
- 二:在這種限制下SQL怎么寫?
最近,在知乎上看到一個有意思的問題,我個人覺得不錯,挺有收獲,在這里跟大家分享一下。
題目:《阿里巴巴JAVA開發手冊》里面寫超過三張表禁止join 這是為什么?這樣的話那sql要怎么寫?
一般,我對於這種問題,解決方案是查詢官方文檔,要么查看我的工具書《高性能的MySQL》,在本書的6.3節:重構查詢的方式里面提到,需要考慮實際情況,看看是否有必要將一個復雜的查詢分解成多個簡單的查詢,並不一定要把所有的工作全都移交給數據庫(轉換思路)!!!
其實Join拆解的核心就是利用In關鍵字,這個也是出自該書,你不信,那我還是只能給你拍照(見下圖)。
所有的問題答案都在書中,這也是我經常推薦大家,要多讀書,讀好書,比如,我經常給你們推薦的書(我又在裝叉了,哈哈)。
計算機解決問題,要么用空間換時間,要么用時間換空間,此二法基本上能解決大多數疑難雜症,你現在看到的各種高大上的玩法,基本上都跟此二法沾親帶故。
比如,該問題下,阿里大佬李晨曦的回答,通過空間換時間的方案來設計表,雖然數據冗余了,但查詢性能顯著提升了,挺有意思。
該大佬的回答如下:
一:為什么做這種限制?
打個比方,如果我有無限的錢,我想買個豪華別墅,想買個跑車,想買個直升飛機,但現實是我沒錢,只能租房住,只能走路上下班。
如果數據庫的性能無限強大,多個表的join肯定是需要的,尤其是復雜的分析型(OLAP)查詢,甚至可能涉及10幾個表的join,但現實是大部分數據庫的性能都太弱了,尤其是涉及到多表join的查詢。給@韓飛點個贊,國內懂這個做這個的太少了,以后就靠他們了。
規范一看就是在使用MySQL時的限制(這種規范實際上迫不得已的限制),做這個限制有兩個原因:一是優化器很弱,涉及多個表的查詢,往往得不到很好的查詢計划,這塊比較復雜,感興趣的朋友可以關注我,我以后會寫文章專門介紹;二是執行器很弱,只有nested loop join,block nested loop join和index nested loop join。
1、nested loop join就是分別從兩個表讀一行數據進行兩兩對比,復雜度是n^2。
2、block nested loop join是分別從兩個表讀很多行數據,然后進行兩兩對比,復雜度也是n^2,只是少了些函數調用等overhead。
3、index nested loop join是從第一個表讀一行,然后在第二個表的索引中查找這個數據,索引是B+樹索引,復雜度可以近似認為是nlogn,比上面兩個好很多,這就是要保證關聯字段有索引的原因。
4、 如果有hash join,就不用做這種限制了,用第一個表(小表)建hash table,第二個表在hash table中查找匹配的項,復雜度是n。缺點是hash table占的內存可能會比較大,不過也有基於磁盤的hash join,實現起來比較復雜。
二:在這種限制下SQL怎么寫?
可是我確實需要兩個表里的數據鏈接在一起啊,我們可以做個冗余,建表的時候,就把這些列放在一個表里,比如一開始有student(id, name),class(id, description),student_class(student_id, class_id)三張表,這樣是符合數據庫范式的(第一范式,第二范式,第三范式,BC范式等),沒有任何冗余,但是馬上就不符合“編程規范“了,那我們可以用一張大表代替它,student_class_full(student_id, class_id, name, description),這樣name和description可能要被存儲多份,但是由於不需要join了,查詢的性能就可以提高很多了。
任何的規范都是在特定情況下的某種妥協,脫離了這個環境,就不一定成立了。
其實,很多同學問我,我是如何解決編程的問題?其實我就是按照以前做數學應用題的方法來解決編程問題,大問題拆分成小問題,小問題在書中就會有相應的例題,照貓畫虎,所有小問題都擊破了,那么,大問題就迎刃而解了,這便是所謂的不攻自破。
其實,你遇到的問題,90%都能通過搜索引擎解決,而你非得要做伸手黨,哎...