Join語句到底可不可用
join語句用于兩個或多個表當中檢索數據。
INNER JOIN或者JOIN 當兩個表當中有匹配的值時,返回行
LEFT JOIN或者LEFT OUTER JOIN? 返回所有左邊的行,即使右表當中沒有相匹配的行
RIGHT JOIN或者RIGHT OUTER JOIN??返回所有右邊的行,即使左表當中沒有相匹配的行
FULL JOIN或FULL OUTER JOIN? 左表或右表有匹配的行時,返回行。
一般在日常生活當中,Join語句通常集中于下面這幾個問題:1.DBA(DataBase Administer數據庫管理員)不讓使用join,使用join有什么問題?2.若有兩個大小不同的表,選擇哪個表作為驅動?
join語句的執行流程
創建兩個表t1,t2,都有主鍵索引id和索引a,給t1插入100行數據,給t2插入1000條數據。
若是直接使用join語句,MySQL的優化器可能會選擇t1或t2作為驅動表,為了方便分析,便限定出驅動表是什么。
select * from t1 straight_join t2 on(t1.a=t2.a)
使用straight_join讓MySQL使用固定的方式執行查詢,t1作為驅動表,t2作為被驅動表。
通過查看explain語句,知道了執行流程為:
1.從表t1中讀取一行數據R?
2.從數據頁R當中取出字段到表t2中去查找滿足的行,當滿足的時候作為結果集的一部分返回
4.在t1中再讀取一行進行對比。
5.直到t1被取完。
這個流程當中,對t1進行全表掃描,對于每一個行R,根據a索引去t2查找,走的是樹查找過程,t1是全表遍歷,總計掃描200行。這個算法稱之為:Index Nested-Loop Join簡稱為NLJ算法。
那么假設不使用join,使用單表查詢來做,首先得select * from t1? 取出t1所有的值,共計100行。然后取出a的值進入t2進行遍歷查詢,返回結果構成一個結果集。我們可以看到不僅多了100多次交互,而且我們還得自己拼接結果集,所以使用join更好。
那么該如何選擇驅動表呢?
通過分析得知,join語句執行過程中,驅動表走全表查詢,被驅動表走樹查詢,可知驅動表越小越好。但是前提是我們可以使用被驅動表的索引下,若果被驅動表不使用索引會是什么情況。
將select語句改為select * from t1 straight_join t2 on(t1.a=t2.b)
b上無索引,所以每次匹配都要做一個全表掃描,這樣子看上去十分繁重,所以InnoDB使用了一個Block Nested-Loop Join算法簡稱BNL算法,實現如下
因為select * 所以我們將t1全表放入到線程內存Join_buffer當中,掃描t2,將t2的每一行與Join_buffe當中的值作比較,由于Join_Buffer是無序的,所以對于t2的每一行,都要走一遍全表判斷,故在內存做判斷數為10萬次。
因為是在內存當中操作,所以會更快。
而且這里是無所謂選什么表作為驅動表的,因為掃描的行數始終為一個表的行數乘上另外一個表的行數。
這里其實還存在著一個問題,要是表的數據過大,join_buffer無法放下一整個表該如何呢?
join_buffer的大小由join_buffer_size決定,默認為256k
處理方法其實很簡單,就是分段放,假設join_buffer只能容納下t1的一半,那么我們先放一半進去,然后掃描t2,將t2當中每一行取出來與t1在join_buffer當中的數據作比較,滿足Join條件的返回結果集,最后判斷結束后,清空join_buffer,將剩下的join_buffer放入繼續判斷。
這種情況下的驅動表選擇是有說法的,驅動表的行數為n,被驅動表為m,n改為x*n(x*n是能放入join_buffer的大小)
1.掃描:n+x*n*m
2.內存判斷:n*m次
我們可以看到x是越小越好的,join_buffer的大小固定,表越小x越小,所以選擇小表作為驅動表。
那么什么是小表,定義是什么呢?
可以讓兩個表都不用索引,按照自己的條件過濾,運行完成之后計算join的各個字段數據量,數據量少的即為小表作為驅動表。