MySQL Join的底層實現原理

mysql只支持一種join算法:Nested-Loop Join(嵌套循環連接),但Nested-Loop Join有三種變種:Simple Nested-Loop Join,Index Nested-Loop Join,Block Nested-Loop Join
(注:參考公衆號:InsideMySQL)


原理:

1.Simple Nested-Loop Join:

如下圖,r爲驅動表,s爲匹配表,可以看到從r中分別取出r1、r2、......、rn去匹配s表的左右列,然後再合併數據,對s表進行了rn次訪問,對數據庫開銷大


webp

微信截圖_20181122171451.png

2.Index Nested-Loop Join(索引嵌套):

這個要求非驅動表(匹配表s)上有索引,可以通過索引來減少比較,加速查詢。
在查詢時,驅動表(r)會根據關聯字段的索引進行查找,擋在索引上找到符合的值,再回表進行查詢,也就是隻有當匹配到索引以後纔會進行回表查詢。
如果非驅動表(s)的關聯健是主鍵的話,性能會非常高,如果不是主鍵,要進行多次回表查詢,先關聯索引,然後根據二級索引的主鍵ID進行回表操作,性能上比索引是主鍵要慢。


webp

微信截圖_20181122171515.png

3.Block Nested-Loop Join:

如果有索引,會選取第二種方式進行join,但如果join列沒有索引,就會採用Block Nested-Loop Join。可以看到中間有個join buffer緩衝區,是將驅動表的所有join相關的列都先緩存到join buffer中,然後批量與匹配表進行匹配,將第一種多次比較合併爲一次,降低了非驅動表(s)的訪問頻率。默認情況下join_buffer_size=256K,在查找的時候MySQL會將所有的需要的列緩存到join buffer當中,包括select的列,而不是僅僅只緩存關聯列。在一個有N個JOIN關聯的SQL當中會在執行時候分配N-1個join buffer。


webp

微信截圖_20181122171528.png


實例:

假設兩張表a 和 b:

a結構:
comments_id        bigInt(20)    P
for_comments_if    mediumint(9)product_id         int(11)order_id           int(11)...

b結構:
id            int(11)       p
comments_id   bigInt(20)product_id    int(11)...

其中b的關聯有comments_id,所以有索引。

join:

SELECT * FROM a gc
JOIN b gcf ON gc.comments_id=gcf.comments_id
WHERE gc.comments_id =2056

使用的是Index Nested-Loop Join,先對驅動表a的主鍵篩選,得到一條,然後對非驅動表b的索引進行seek匹配,預計得到一條數據。

下面這種情況沒用到索引:

SELECT * FROM a gc
JOIN b gcf ON gc.order_id=gcf.product_id

使用Block Nested-Loop Join,如果b表數據少,作爲驅動表,將b的需要的數據緩存到join buffer中,批量對a表掃描

left join:

SELECT * FROM a gc
LEFT JOIN b gcf ON gc.comments_id=gcf.comments_id

這裏用到了索引,所以會採用Index Nested-Loop Join,因爲沒有篩選條件,會選擇一張表作爲驅動表去進行join,去關聯非驅動表的索引。

如果加了條件:

SELECT * FROM b gcf
LEFT JOIN a gc ON gc.comments_id=gcf.comments_id
WHERE gcf.comments_id =2056

就會從驅動表篩選出一條來進行對非驅動表的匹配。


left join:會保全左表數據,如果右表沒相關數據,會顯示null
fight join:會保全右表數據,如果左表沒相關數據,會顯示null
inner join:部分主從表,結果會取兩個錶針對on條件相匹配的最小集



鏈接:https://www.jianshu.com/p/16ad9669d8a9


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章