mysql只支持一種join算法:Nested-Loop Join(嵌套循環鏈接),但Nested-Loop Join有三種變種:Simple Nested-Loop Join,Index Nested-Loop Join,Block Nested-Loop Join
(注:參考公衆號:InsideMySQL)mysql
以下圖,r爲驅動表,s爲匹配表,能夠看到從r中分別取出r一、r二、......、rn去匹配s表的左右列,而後再合併數據,對s表進行了rn次訪問,對數據庫開銷大web
微信截圖_20181122171451.png算法
這個要求非驅動表(匹配表s)上有索引,能夠經過索引來減小比較,加速查詢。
在查詢時,驅動表(r)會根據關聯字段的索引進行查找,擋在索引上找到符合的值,再回表進行查詢,也就是隻有當匹配到索引之後纔會進行回表查詢。
若是非驅動表(s)的關聯健是主鍵的話,性能會很是高,若是不是主鍵,要進行屢次回表查詢,先關聯索引,而後根據二級索引的主鍵ID進行回表操做,性能上比索引是主鍵要慢。sql
微信截圖_20181122171515.png數據庫
若是有索引,會選取第二種方式進行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。緩存
微信截圖_20181122171528.png微信
假設兩張表a 和 b:ide
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,因此有索引。oop
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表掃描
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