掌握MySQL連接配接查詢到底什麼是驅動表
準備我們需要的表結構和資料
兩張表 studnet(學生)表和score(成績)表, 建立表的SQL語句如下
CREATE TABLE
student
( id
int(11) NOT NULL, no
varchar(20) DEFAULT NULL, name
PRIMARY KEY ( id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
score
id
no
chinese
double(4,0) DEFAULT NULL, math
engilsh
id
MySQL連接配接查詢分為以下三種
left join 左連接配接,用法如下,這種查詢會把左表(student)所有資料查詢出來,右表不存在的用空表示,結果圖如下
select * from student s1 left join score s2 on s1.on = s2. on
right join 右連接配接, 用法如下,這種查詢會把右表(score)所有資料查詢出來,左表不存在的用空表示,結果圖如下
select * from student s1 right join score s2 on s1.no = s2.no
inner join 内連接配接,用法如下,這種查詢會把左右表都存在的資料查詢出來,不存在資料忽略,結果圖如下
select * from student s1 inner join score s2 on s1.no = s2.no
連接配接查詢中需要注意的點
什麼是驅動表,什麼是被驅動表,這兩個概念在查詢中有時容易讓人搞混,有下面幾種情況,大家需要了解。
當連接配接查詢沒有where條件時,左連接配接查詢時,前面的表是驅動表,後面的表是被驅動表,右連接配接查詢時相反,内連接配接查詢時,哪張表的資料較少,哪張表就是驅動表
當連接配接查詢有where條件時,帶where條件的表是驅動表,否則是被驅動表
怎麼确定我們上面的兩種情況呢,執行計劃是不會騙人的,我們針對上面情況分别看看執行計劃給出的答案
首先第一種情況,student表中3條資料,score表中2條資料,但兩張表中隻有一條資料是關聯的(編号是1),看如下SQL查詢
//左連接配接查詢
explain select * from student s1 left join score s2 on s1.no = s2.no
//右連接配接查詢
explain select * from student s1 right join score s2 on s1.no = s2.no
//内連接配接查詢
explain select * from student s1 inner join score s2 on s1.no = s2.no
執行計劃中靠前的表是驅動表,我們看下面三種圖中,是不是全度符合情況一,第一張圖中s1是驅動表,第二張圖中s2是驅動表,第三種途中s2是驅動表
其次第二種情況,還是上面三種SQL語句,我們分别加上where條件,再來看看執行計劃的結果是什麼樣呢?
explain select * from student s1 left join score s2 on s1.no = s2.no
where s2. no = 1
explain select * from student s1 right join score s2 on s1.no = s2.no
where s1.no = 1
explain select * from student s1 inner join score s2 on s1.no = s2.no
我們看下面三種執行計劃結果,全都以where條件為準了,而且跟上面情況一的都相反了,是以情況二也是得到了驗證.
連接配接查詢優化
要了解連接配接查詢優化,得先了解連接配接查詢的算法,連接配接查詢常用的一共有兩種算法,我們簡要說明一下
Simple Nested-Loop Join Algorithms (簡單嵌套循環連接配接算法)
比如上面的查詢中,我們确定了驅動表和被驅動表,那麼查詢過程如下,很簡單,就是雙重循環,從驅動表中循環擷取每一行資料,再在被驅動表比對滿足條件的行。
for (row1 : 驅動表) {
for (row2 : 被驅動表){
if (conidtion == true){
send client
}
}
}
Index Nested-Loop Join Algorithms (索引嵌套循環連接配接算法)
上面雙重for循環的查詢中,相信很多研發人員看到這種情況第一個想法就是性能問題,是的,join查詢的優化思路就是小表驅動大表,而且在大表上建立索引(也就是被動表建立索引),如果驅動表建立了索引,MySQL是不會使用的
索引在被驅動表中命中,不用再周遊被驅動表了
Block Nested-Loop Join Algorithm(基于塊的連接配接嵌套循環算法)
其實很簡單就是把一行變成了一批,塊嵌套循環(BNL)嵌套算法使用對在外部循環中讀取的行進行緩沖,以減少必須讀取内部循環中的表的次數。例如,如果将10行讀入緩沖區并将緩沖區傳遞到下一個内部循環,則可以将内部循環中讀取的每一行與緩沖區中的所有10行進行比較。這将内部表必須讀取的次數減少了一個數量級。
MySQL連接配接緩沖區大小通過這個參數控制 : join_buffer_size
MySQL連接配接緩沖區有一些特征,隻有無法使用索引時才會使用連接配接緩沖區;聯接中隻有感興趣的列存儲在其聯接緩沖區中,而不是整個行;為每個可以緩沖的連接配接配置設定一個緩沖區,是以可以使用多個連接配接緩沖區來處理給定查詢;在執行連接配接之前配置設定連接配接緩沖區,并在查詢完成後釋放連接配接緩沖區
是以查詢時最好不要把 * 作為查詢的字段,而是需要什麼字段查詢什麼字段,這樣緩沖區能夠緩沖足夠多的行。
從上面的執行計劃中其實我們已經看到了 useing join buffer了,是的,那是因為我們對兩張表都有建立索引
三種算法優先級
第一種算法忽略,MySQL不會采用這種的,當我們對被驅動表建立了索引,那麼MySQL一定使用的第二種算法,當我們沒有建立索引或者對驅動表建立了索引,那麼MySQL一定使用第三種算法
MySQL連接配接算法官方文檔
https://dev.mysql.com/doc/refman/8.0/en/nested-loop-joins.html原文位址
https://www.cnblogs.com/sy270321/p/12760211.html