Mysql表連接的執(zhí)行流程詳解
1. 前言
對于連接操作,驅動表和被驅動表的關聯(lián)條件我們放在on后面,如果額外增加對驅動表和被驅動表的過濾條件,放到on或者where后面都不會報錯,但是得到的結果集卻是不一樣的???
1.1 mysql連接的原理
眾所周知,mysql是基于嵌套循環(huán)連接(Nested-Loop Join,暫不考慮優(yōu)化算法)算法來進行表之間的連接操作的,大致過程如下:
- 選取驅動表,使用與驅動表相關的過濾條件執(zhí)行對驅動表的單表查詢;
- 對于查詢到的驅動表中的每一條紀錄,分別到被驅動表中查找匹配的紀錄。
偽代碼如下:
for each row in t1 { // 遍歷滿足對t1單表查詢結果集中的每一條紀錄
for each row in t2 { // 對于某條t1紀錄,遍歷滿足對t2單表查詢結果集中的每一條紀錄
if row satisfies join conditions, send to client
}
}1.2 show warnings命令
我們寫的sql語句,在經過優(yōu)化器優(yōu)化后才會交給執(zhí)行器執(zhí)行,而show warnings命令則可以幫助我們獲得優(yōu)化器優(yōu)化后的sql。
2. 準備工作
表結構如下:
CREATE TABLE `student` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `stu_code` varchar(20) NOT NULL DEFAULT '', `stu_name` varchar(30) NOT NULL DEFAULT '', `stu_sex` varchar(10) NOT NULL DEFAULT '', `stu_age` int(10) NOT NULL DEFAULT '0', `stu_dept` varchar(30) NOT NULL DEFAULT '', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uq_stu_code` (`stu_code`) ) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8mb4 CREATE TABLE `course` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `cou_code` varchar(20) NOT NULL DEFAULT '', `cou_name` varchar(50) NOT NULL DEFAULT '', `cou_score` int(10) NOT NULL DEFAULT '0', `stu_code` varchar(20) NOT NULL DEFAULT '', PRIMARY KEY (`id`) USING BTREE, KEY `idx_stu_code_cou_code` (`stu_code`,`cou_code`) ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4
表數(shù)據(jù)如下:

3. inner join內連接on、where的區(qū)別
sql如下:
select * from student inner join course on student.stu_code = course.stu_code and student.stu_code >= 3 and course.cou_score >= 80;
執(zhí)行explain+sql命令:

執(zhí)行show warnings命令:

分析:從show warnings分析來看,對于inner join連接,經過優(yōu)化器優(yōu)化后,on連接條件會轉化為where!也就是說內連接中的where和on是等價的。
4. left join左連接on、where的區(qū)別
4.1 where驅動表過濾條件
sql如下:
select * from student left join course on student.stu_code = course.stu_code where student.stu_code >= 3;
執(zhí)行explain+sql命令:

執(zhí)行show warnings命令:

結果集:

分析:從explain分析看出,student作為驅動表,把student.stu_code >= 3作為過濾條件進行全表掃描,然后把查詢到的每條紀錄的student.stu_code(也就是on條件里面的)分別作為過濾條件讓被驅動表course做單表查詢。
4.2 on驅動表過濾條件
sql如下:
select * from student left join course on student.stu_code = course.stu_code and student.stu_code >= 3;
執(zhí)行explain+sql命令:

執(zhí)行show warnings命令:

結果集:

從結果集來看,student.stu_code >= 3并未生效,為什么?
分析:從explain分析看出,student作為驅動表,做全表掃描,然后把查詢到的每條記錄的student.stu_code和student.stu_code >= 3(也就是on條件里面的)分別做為過濾條件讓被驅動表做單表查詢;此時student.stu_code >= 3對驅動表是不過濾的,僅在連接被驅動表時生效,查詢不到符合紀錄而返回NULL!
4.3 on被驅動表過濾條件
sql如下:
select * from student left join course on student.stu_code = course.stu_code and course.cou_score >= 80;
執(zhí)行explain+sql命令:

執(zhí)行show warnings命令:

結果集:

分析:從explain分析看出,student作為驅動表,做全表掃描,然后把查詢到的每條記錄的student.stu_code和course.cou_score >= 80(也就是on條件里面的)分別做為過濾條件讓被驅動表做單表查詢;
4.4 where被驅動表過濾條件
sql如下:

執(zhí)行explain+sql命令:

執(zhí)行show warnings命令:

結果集:

從show warnings分析來看?left join連接變成了inner join連接?
分析:從show warnings分析看出,如果被驅動表有過濾條件在where,那么left join會被失效,被優(yōu)化成inner join連接。所以被驅動表的過濾條件應該放在on而不是where。
5. 總結
其實,在內連接的基礎上引入外連接的概念,就是為了解決驅動表中的紀錄即使沒有在被驅動表中找到匹配的紀錄,仍要加入結果集的問題。所以對于外連接(外連接包括:左連接、右連接),被驅動表的過濾條件我們應該放在on!
到此這篇關于Mysql表連接的執(zhí)行流程詳解的文章就介紹到這了,更多相關Mysql表連接 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MySQL與PHP的基礎與應用專題之創(chuàng)建數(shù)據(jù)庫表
MySQL是一個關系型數(shù)據(jù)庫管理系統(tǒng),由瑞典MySQL AB 公司開發(fā),屬于 Oracle 旗下產品。MySQL 是最流行的關系型數(shù)據(jù)庫管理系統(tǒng)之一,本系列將帶你掌握php與mysql的基礎應用,本篇從數(shù)據(jù)庫的創(chuàng)建開始2022-02-02
mysql5.5 master-slave(Replication)主從配置
在主機master中對test數(shù)據(jù)庫進行sql操作,再查看從機test數(shù)據(jù)庫是否產生同步。2011-07-07
MySQL數(shù)據(jù)時區(qū)問題以及datetime和timestamp類型存儲的差異
這篇文章主要介紹了MySQL數(shù)據(jù)時區(qū)問題以及datetime和timestamp類型存儲的差異,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
MySQL group by和left join并用解決方式
這篇文章主要介紹了MySQL group by和left join并用解決方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12
mysql中數(shù)據(jù)庫與數(shù)據(jù)表編碼格式的查看、創(chuàng)建及修改
這篇文章給大家介紹了如何查看、創(chuàng)建以及修改數(shù)據(jù)庫與數(shù)據(jù)表的編碼格式,另外還給大家分享了添加和刪除外鍵的示例代碼,文中介紹的很詳細,對大家的理解和學習具有一定的參考借鑒價值,有需要的朋友們下面來一起學習學習吧。2016-11-11

