MySQL中的表連接原理分析
1、背景
在進(jìn)行sql查詢時(shí)有時(shí)需要多張表的查詢結(jié)果組成一個(gè)共同的結(jié)果返回,這時(shí)就用到了mysql中連接的用法,接下來(lái)就以兩張表來(lái)講解表連接的原理。
2、環(huán)境
創(chuàng)建兩張表并插入數(shù)據(jù)如下:
mysql> select * from testjoin1; +----+------+------+ | id | str1 | num1 | +----+------+------+ | 1 | aaa | 111 | | 2 | bbb | 222 | | 3 | ccc | 333 | +----+------+------+ 3 rows in set (0.00 sec) mysql> select * from testjoin2; +----+------+------+ | id | str2 | num2 | +----+------+------+ | 1 | bbb | 333 | | 2 | ccc | 444 | | 3 | ddd | 555 | +----+------+------+ 3 rows in set (0.00 sec)
3、表連接原理
【1】驅(qū)動(dòng)表和被驅(qū)動(dòng)表
兩張表連接查詢過(guò)程為:
- 1、先確定第一張要查詢的表得到第一張表的查詢結(jié)果,
- 2、第一張表的查詢結(jié)果作為第二張表的查詢條件進(jìn)行查詢得到最終查詢結(jié)果。
其中第一張表叫驅(qū)動(dòng)表,第二張表叫被驅(qū)動(dòng)表,先看一下最基本連接查詢的例子:
mysql> select * from testjoin1, testjoin2; +----+------+------+----+------+------+ | id | str1 | num1 | id | str2 | num2 | +----+------+------+----+------+------+ | 3 | ccc | 333 | 1 | bbb | 333 | | 2 | bbb | 222 | 1 | bbb | 333 | | 1 | aaa | 111 | 1 | bbb | 333 | | 3 | ccc | 333 | 2 | ccc | 444 | | 2 | bbb | 222 | 2 | ccc | 444 | | 1 | aaa | 111 | 2 | ccc | 444 | | 3 | ccc | 333 | 3 | ddd | 555 | | 2 | bbb | 222 | 3 | ddd | 555 | | 1 | aaa | 111 | 3 | ddd | 555 | +----+------+------+----+------+------+ 9 rows in set (0.00 sec)
再看一下執(zhí)行計(jì)劃:
mysql> explain select * from testjoin1, testjoin2;
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+----------------
---------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra
|
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+----------------
---------------+
| 1 | SIMPLE | testjoin1 | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | NULL
|
| 1 | SIMPLE | testjoin2 | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | Using join buff
er (hash join) |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+----------------
---------------+
2 rows in set, 1 warning (0.00 sec)
可以看到執(zhí)行計(jì)劃輸出了兩條,第一條代表testjoin1表是驅(qū)動(dòng)表, testjoin2表是被驅(qū)動(dòng)表。
【2】?jī)?nèi)連接
驅(qū)動(dòng)表的查詢結(jié)果作為查詢條件但沒(méi)有在被驅(qū)動(dòng)表中匹配到結(jié)果時(shí),這條記錄就不會(huì)加入到最終結(jié)果集中,這種連接方式就叫內(nèi)連接,例如:
mysql> select * from testjoin1 inner join testjoin2 on str1=str2; +----+------+------+----+------+------+ | id | str1 | num1 | id | str2 | num2 | +----+------+------+----+------+------+ | 2 | bbb | 222 | 1 | bbb | 333 | | 3 | ccc | 333 | 2 | ccc | 444 | +----+------+------+----+------+------+ 2 rows in set (0.00 sec)
可以看到testjoin1表中str1為aaa的記錄就不在查詢結(jié)果中,用圖紅色部分表示:

【3】外連接
與內(nèi)連接相對(duì)應(yīng)的就是外連接,外連接中驅(qū)動(dòng)表的查詢結(jié)果作為查詢條件即使沒(méi)有在被驅(qū)動(dòng)表中查到,也會(huì)展示在最終結(jié)果集中,外連接分為左外連接和右外連接,左外連接就是將左邊的表作為驅(qū)動(dòng)表,左外連接查詢?nèi)缦拢?/p>
mysql> select * from testjoin1 left join testjoin2 on str1=str2; +----+------+------+------+------+------+ | id | str1 | num1 | id | str2 | num2 | +----+------+------+------+------+------+ | 1 | aaa | 111 | NULL | NULL | NULL | | 2 | bbb | 222 | 1 | bbb | 333 | | 3 | ccc | 333 | 2 | ccc | 444 | +----+------+------+------+------+------+ 3 rows in set (0.00 sec)
用圖紫色部分表示:

右外連接就是將右邊的表作為驅(qū)動(dòng)表,右外連接查詢?nèi)缦拢?/p>
mysql> select * from testjoin1 right join testjoin2 on str1=str2; +------+------+------+----+------+------+ | id | str1 | num1 | id | str2 | num2 | +------+------+------+----+------+------+ | 2 | bbb | 222 | 1 | bbb | 333 | | 3 | ccc | 333 | 2 | ccc | 444 | | NULL | NULL | NULL | 3 | ddd | 555 | +------+------+------+----+------+------+ 3 rows in set (0.00 sec)
用圖綠色部分表示:

【4】嵌套循環(huán)連接
驅(qū)動(dòng)表只會(huì)被訪問(wèn)一次,被驅(qū)動(dòng)表可能被訪問(wèn)多次,取決于從驅(qū)動(dòng)表中得到的結(jié)果,這種連接執(zhí)行方式就叫嵌套循環(huán)連接。
【5】join buffer
mysql中的查表過(guò)程就是把數(shù)據(jù)從磁盤中加載到內(nèi)存進(jìn)行比較查詢,加載后面的記錄時(shí)會(huì)釋放內(nèi)存中前面已經(jīng)使用過(guò)的記錄,我們上面說(shuō)過(guò)被驅(qū)動(dòng)表可能會(huì)被訪問(wèn)很多次,每次都從磁盤重新加載數(shù)據(jù)到內(nèi)存無(wú)疑會(huì)增加開(kāi)銷,所以提出了join buffer,也就是存儲(chǔ)驅(qū)動(dòng)表的所有查詢結(jié)過(guò),然后只執(zhí)行一次將被驅(qū)動(dòng)表從磁盤加載到內(nèi)存中,在內(nèi)存中計(jì)算得到最終查詢結(jié)果,前面測(cè)試連接的explain語(yǔ)句中就可以看到被驅(qū)動(dòng)表的Extra字段中有Using join buffer。
4、總結(jié)
對(duì)驅(qū)動(dòng)表進(jìn)行查詢時(shí)就相當(dāng)于單表查詢,也可以通過(guò)索引去優(yōu)化查詢速度,當(dāng)確定了驅(qū)動(dòng)表的查詢結(jié)果時(shí),其實(shí)被驅(qū)動(dòng)的查詢條件也就確定了,也可以通過(guò)加索引去優(yōu)化查詢速度,當(dāng)然索引是否生效還要看和全表掃描的執(zhí)行效率進(jìn)行對(duì)比。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
一文搞懂MySQL XA如何實(shí)現(xiàn)分布式事務(wù)
MySQL如何實(shí)現(xiàn)多個(gè)MySQL數(shù)據(jù)庫(kù)更新的一致性呢?那就是MySQL XA,本文就來(lái)介紹一下MySQL XA如何實(shí)現(xiàn)分布式事務(wù),具有一定的參考價(jià)值,感興趣的可以了解一下2021-11-11
MySQL中使用SQL語(yǔ)句查看某個(gè)表的編碼方法
下面小編就為大家?guī)?lái)一篇MySQL中使用SQL語(yǔ)句查看某個(gè)表的編碼方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11
mysql通過(guò)binlog定時(shí)備份數(shù)據(jù)庫(kù)與恢復(fù)的方法
這篇文章主要介紹了mysql通過(guò)binlog定時(shí)備份數(shù)據(jù)庫(kù)與恢復(fù)的方法,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-12-12
解決MySQL 5.7.9版本sql_mode=only_full_group_by問(wèn)題
這篇文章主要介紹了解決MySQL 5.7.9版本sql_mode=only_full_group_by問(wèn)題,需要的朋友可以參考下2017-05-05
設(shè)置Mysql5.6允許外網(wǎng)訪問(wèn)的詳細(xì)流程分享
今天小編就為大家分享一篇設(shè)置Mysql5.6允許外網(wǎng)訪問(wèn)的詳細(xì)流程分享,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05

