現在有表t,r,表t有a,b欄位,表r有c,d欄位,a欄位和c欄位有建立索引,表t有100000行資料,表r有6行資料。
我們先來普通的join語句,在join語句中,存在驅動表和被驅動表,mysql會已小表已用來驅動大表,小表就是資料量較小的那個。
例如執行如下語句,我們就會看來是用表r驅動表t的
explain
select
*from t join r on r.c = t.a;
看到的情況如下:
表r走全表掃瞄,表t走索引c,我們就可以想到join的執行流程如下:
表r走全表掃瞄,從表r中取到一行符合條件的資料。
拿到這行資料去表t中走索引c。
查到符合條件的資料,則加入結果集。
重複上述步驟,直到走完表r。
在這個過程中,對驅動表r走全表掃瞄,也就是掃瞄了6行;對被驅動表t走索引c,每乙個資料都只需要掃瞄一行,也就是6行,所以整個流程掃瞄的行數為12行。
join是用小表驅動大表,那有指定驅動表的嘛?有的,straight_join
33.1 straight_join
通過如下語句,我們就能指定,前表為驅動表,後表為被驅動表。
select
*from t straight_join r on r.c = t.a;
通過下圖,我們能明顯看出,表t就是驅動表,走的全表掃瞄,一次join流程的掃瞄行數達到了100006行之多,所以如何如何選擇驅動也是乙個問題。
如何選擇驅動表:
首先,明白一點,驅動錶走全表掃瞄,被驅動錶走索引。
先假設驅動表有n行資料,被驅動表有m行資料,那它掃瞄的總行數為 n + n * 2 * log2m,因為 每次搜尋一棵樹近似複雜度是以 2 為底的 m 的對數,記為 log2m ,走索引a之後再進行回表,需要需要乘以2。
從上述公式能很容易看出,驅動表的資料行數大小起決定性的作用。
**在不用join情況下:**我們還是從小表出發
通過select * from r
來獲取資料集合。
掃瞄資料集合,依次一行一行取出去表t中進行配對。
它的掃瞄總行數為18行,也就是比之前用小表驅動大表的方式多了6次掃瞄行數。
現在我們,來看下,用不上索引的情況。
不過,這個需要介紹下,mysql當可以走被驅動表索引時,用的演算法為****** nested-loop join ,沒用索引時用的演算法為 block nested-loop join ,下面,我們就來說他。
上圖顯示了,表t使用join buffer。
由於被驅動表是沒有可用索引的,它的演算法流程如下:
但是有個問題,上述的情況是建立在join_buffer放的下表r的情況,那如何放不下?
mysql提供引數join_buffer_size
來控制join_buffer大小,預設大小為256k。如果放不下整張表,就將表進行分段放置,它會在第一輪對比結束後,清空join_buffer,再加入新的表r資料。
現在我們來假設下,驅動表的資料行數是 n行,完全加入join_buffer需要分 k 段,被驅動表的資料行數是 m行。
那我們掃瞄的行數就是n+ceil(n/k)*m,我們可以看出,影響的主要因素是k,也就join_buffer的大小,它越小,就可以較少對被驅動表的掃瞄次數。
MySQL的JOIN(二) JOIN原理
nested loop join nlj 演算法 首先介紹一種基礎演算法 nlj,巢狀迴圈演算法。迴圈外層是驅動表,循壞內層是被驅動表。驅動表會驅動被驅動表進行連線操作。首先驅動表找到第一條記錄,然後從頭掃瞄被驅動表,逐一查詢與驅動表第一條記錄匹配的記錄然後連線起來形成結果表中的一條記。被驅動表查詢...
Mysql面試(四) join語句相關
驅動表,被驅動表 我們將兩張表進行join語句關聯時,例如,假設有t1表 id int primarykey id a int key a b int t2表 id int primarykey id a int key a b int t1和t2都有主鍵索引id和普通索引a,t1有100條資料,t...
MySQL 34 join語句優化
join 語句的兩種實現演算法分別是 index nested loop join和 block nested loop join,針對於這兩個演算法都還有相應的優化方法。在這之前,我們先介紹下mrr優化。34.1multi range read 優化 multi range read優化 mrr ...