掌握MySQL鏈接查詢到底什麼是驅動表html
準備咱們須要的表結構和數據
兩張表 studnet(學生)表和score(成績)表, 建立表的SQL語句以下
mysql
CREATE TABLE student
(id
int(11) NOT NULL,no
varchar(20) DEFAULT NULL,name
varchar(20) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
算法
CREATE TABLE score
(id
int(11) NOT NULL,no
varchar(20) DEFAULT NULL,chinese
double(4,0) DEFAULT NULL,math
double(4,0) DEFAULT NULL,engilsh
double(4,0) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
MySQL鏈接查詢分爲如下三種
left join 左鏈接,用法以下,這種查詢會把左表(student)全部數據查詢出來,右表不存在的用空表示,結果圖以下
sql
select * from student s1 left join score s2 on s1.on = s2. onoop
right join 右鏈接, 用法以下,這種查詢會把右表(score)全部數據查詢出來,左表不存在的用空表示,結果圖以下性能
select * from student s1 right join score s2 on s1.no = s2.no優化
inner join 內鏈接,用法以下,這種查詢會把左右表都存在的數據查詢出來,不存在數據忽略,結果圖以下url
select * from student s1 inner join score s2 on s1.no = s2.no.net
鏈接查詢中須要注意的點
什麼是驅動表,什麼是被驅動表,這兩個概念在查詢中有時容易讓人搞混,有下面幾種狀況,你們須要瞭解。
code
當鏈接查詢沒有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 s1.no = 1
咱們看下面三種執行計劃結果,全都以where條件爲準了,並且跟上面狀況一的都相反了,所以狀況二也是獲得了驗證.
鏈接查詢優化
要理解鏈接查詢優化,得先理解鏈接查詢的算法,鏈接查詢經常使用的一共有兩種算法,咱們簡要說明一下
Simple Nested-Loop Join Algorithms (簡單嵌套循環鏈接算法)
好比上面的查詢中,咱們肯定了驅動表和被驅動表,那麼查詢過程以下,很簡單,就是雙重循環,從驅動表中循環獲取每一行數據,再在被驅動表匹配知足條件的行。
for (row1 : 驅動表) {
for (row2 : 被驅動表){ if (conidtion == true){ send client } }
}
Index Nested-Loop Join Algorithms (索引嵌套循環鏈接算法)
上面雙重for循環的查詢中,相信不少研發人員看到這種狀況第一個想法就是性能問題,是的,join查詢的優化思路就是小表驅動大表,並且在大表上建立索引(也就是被動表建立索引),若是驅動表建立了索引,MySQL是不會使用的
for (row1 : 驅動表) {
索引在被驅動表中命中,不用再遍歷被驅動表了
}
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