最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL兩個表的親密接觸-連接查詢的原理分析

 更新時間:2024年01月24日 09:09:39   作者:廈門微思網(wǎng)絡(luò)  
這篇文章主要介紹了MySQL兩個表的親密接觸-連接查詢的原理,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

MySQL對于被驅(qū)動表的關(guān)聯(lián)字段沒索引的關(guān)聯(lián)查詢,一般都會使用 BNL 算法。如果有索引一般選擇 NLJ 算法,有 索引的情況下 NLJ 算法比 BNL算法性能更高。

關(guān)系型數(shù)據(jù)庫還有一個重要的概念:Join(連接)。使用Join有好處,也會壞處,只有我們明白了其中的原理,才能更多的使用Join。切記不可以:

業(yè)務(wù)之上,再復(fù)雜的查詢也在一個連表語句中完成。

敬而遠(yuǎn)之,DBA每次上報的慢查詢都是連接查詢導(dǎo)致的,我再也不用了。

連接的本質(zhì)

我們先來創(chuàng)建兩個簡單的表,再初始化一些數(shù)據(jù)

CREATE TABLE t1 (m1 int, n1 varchar(1));
 
CREATE TABLE t2 (m2 int, n2 varchar(1));
 
INSERT INTO t1 VALUES(1, 'a'), (2 , 'b') ,(3 ,'c') ;
 
INSERT INTO t2 VALUES(2 , 'b'), (3 , 'c '),(4 , 'd');

從本質(zhì)上來說,連接就是把各個表的數(shù)據(jù)都取出來進行匹配,t1 和 t2 的兩個表連接起來就是這樣的:

連接語法:

select * from t1, t2;

如果樂意,我們可以連接任意數(shù)量的表。但是如果不加任何限制條件的話,這個數(shù)據(jù)量是非常大的,我們現(xiàn)實中使用都是會加上限制條件的。

我們來看下下面這條語句

select * from t1,t2 where t1.m1 > 1 and t1.m1 = t2.m2 and t2.n2 = 'c';

這個連接查詢的執(zhí)行過程大致如下

首先確定第一個需要查詢 表稱為驅(qū)動表(t1)

步驟1中從驅(qū)動表 (t1) 中每獲得一條記錄,都要去被驅(qū)動表 (t2) 中查詢匹配。

從上面的步驟,可以看出上述的連表查詢我們需要查詢一次t1,兩次t2。也就是說,兩表的連接查詢中,需要查詢一次驅(qū)動表,被驅(qū)動表需要查詢多次。

這里需要注意下,并不是將所有滿足條件的驅(qū)動表記錄先查詢出來放到一個地方,然后再去被驅(qū)動表中查詢,(如果滿足條件的驅(qū)動表中的數(shù)據(jù)非常多,那要需要多大的內(nèi)存呀。) 所以是每獲得一條驅(qū)動表記錄就去被驅(qū)動表中查詢。

內(nèi)連接和外連接

我們再來創(chuàng)建兩個表,并插入一些數(shù)據(jù)

CREATE TABLE student ( 
number INT NOT NULL Auto_increment comment'學(xué)號',
name varchar (5) COMMENT '姓名',
major varchar (30) comment '專業(yè)',
PRIMARY KEY (number));
 
CREATE TABLE score ( 
number INT  comment'學(xué)號',
subject varchar (30) COMMENT '科目',
score TINYINT  comment '成績',
PRIMARY KEY (number, subject));
 
 
INSERT INTO `student` (`number`, `name`, `major`) 
VALUES ('20230301', '小趙', '計算機科學(xué)');
INSERT INTO `student` (`number`, `name`, `major`) 
VALUES ('20230302', '小錢', '通信');
INSERT INTO `student` (`number`, `name`, `major`) 
VALUES ('20230303', '小孫', '土木工程');
 
INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230301', '高等數(shù)學(xué)', '60');
INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230301', '英語', '70');
INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230302', '高等數(shù)學(xué)', '80');
INSERT INTO `score` (`number`, `subject`, `score`) 
VALUES ('20230302', '英語', '90');

如果我們想把所有的學(xué)生的成績都查出來,只需要這樣執(zhí)行:

select s1.number, s1.name, s1.major, s2.subject, s2.score 
  from student as s1 , score as s2 
where s1.number = s2.number;

有個問題就是小孫因為某些原因沒有參加考試,所以在結(jié)果表中沒有對應(yīng) 的成績記錄。如果老師想查看所有學(xué)生的考試成績,即使是缺考的學(xué)生 他們的成績也應(yīng)該展示出來。

為了解決這個問題,就有了內(nèi)連接和外連接的概念:

  • 對于內(nèi)連接的兩個表,若驅(qū)動表中的記錄在被驅(qū)動表找不到匹配的記錄,則該記錄不會加入到最后的結(jié)果集。前面提到的連接都是內(nèi)連接。
  • 對于外連接的兩個表,時驅(qū)動表中的記錄在被驅(qū)動表中沒有匹配的記錄,也仍然需要加入到結(jié)果集。

MySQL 中,根據(jù)選取的驅(qū)動表的不同,外連接可以細(xì)分為

  • 左外連接 選取左側(cè)的表為驅(qū)動表。
  • 右外連接·選取右側(cè)的表為驅(qū)動表。

當(dāng)我們使用外連接的時候 有時候我們也不想把驅(qū)動表的全部記錄都加入到最后的結(jié)果集中,這個時候我們就要使用過濾條件了。

  • WHERE 子句中的過濾條件:不論是內(nèi)連接還是外連接 凡是不符合 WHERE 子句中過濾條件的記錄都不會被加入到最后的結(jié)果集。
  • ON 子句中的過濾條件:對于外連接的驅(qū)動表中的記錄來說,如果無法在被驅(qū)動表中找到匹配 ON 子句 中過濾條件的記錄 那么該驅(qū)動表記錄仍然會被加入到結(jié)果集中,對應(yīng)的被驅(qū)動表記錄的各個字段使用NULL 值填充。

所以上述的需求我們可以左查詢這樣來做:

select s1.number, s1.name, s1.major, s2.subject, s2.score 
  from student as s1 left join score as s2 
on s1.number = s2.number;

語法:

#左連接
select * from t1 left join t2 on '連接條件' where '普通過濾條件'
#右連接
select * from t1 right join t2 on '連接條件' where '普通過濾條件'

內(nèi)連接的另一種寫法,也是常用寫法

select s1.number, s1.name, s1.major, s2.subject, s2.score 
  from student as s1 inner join score as s2 
where s1.number = s2.number;

語法:

select * from t1 inner join t2 on '連接條件' where '過濾條件'

連接原理

上述說了這么多,知識簡單回顧一下連接,左連接,右連接這些概念。

接下來我們重點說一下 MySQL 采用了什么樣的算法來進行表與表之前的連接。

Nested-Loop Join (嵌套循環(huán)連接) NLJ

前面我們已經(jīng)介紹過了執(zhí)行連接查詢的大致步驟了,我們再來簡單回顧一下

  • 步驟1:選取驅(qū)動表,使用相關(guān)的過濾條件,選取代價最低的單表訪問方法來執(zhí)行訪問。
  • 步驟2:對步驟1中查詢到的驅(qū)動表結(jié)果中的每一條記錄,都分別在被驅(qū)動表中匹配符合條件的記錄。
  • 如果有三個表,那么步驟2中得到的結(jié)果集就像是新的驅(qū)動表,然后第三個表就成為了驅(qū)動表,重復(fù)上述的過程。

整個過程就像是一個嵌套循環(huán),所以這種連接方式稱為 嵌套循環(huán)連接 ,這是最簡單也是最笨的一種連接查詢算法。

大致處理過程如下:

for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions, send to client
    }
  }
}

需要注意的是對于獲套循環(huán)連接算法法來說,每當(dāng)我們從驅(qū)動表中得到了一條記錄時,就根據(jù)這條記錄立時到被驅(qū)動表中查詢一次,如果得到了匹配的記錄, 就把組合后 的記錄發(fā)送給客戶端,然后再到驅(qū)動表中獲取下一條記錄。這個過程將重復(fù)進行。

有什么方式可以優(yōu)化嗎

使用索引加快連接速度

這個是我們比較熟悉的方式,也是相對來說最有用的方式,在被驅(qū)動表上創(chuàng)建合適的索引,只返回必要的字段等都可以起到一些優(yōu)化的作用。

Block Nested-Loop Join(塊嵌套循環(huán)連接)BNL

每次訪問被驅(qū)動表,其表中的記錄都會被加載到內(nèi)存中,然后再從驅(qū)動表中取出一條與其匹配,匹配結(jié)束后清楚內(nèi)存,然后再從驅(qū)動表中加載一條記錄,然后把被驅(qū)動表的記錄加載到內(nèi)存匹配,如果這個被驅(qū)動表中的數(shù)據(jù)特別多而且不能使用索引進行訪問,那就相當(dāng)于要從磁盤上讀這個表好多次,這個IO的代價就非常大了。所以我們得想辦法,盡量減少被驅(qū)動表的訪問次數(shù),于是就出現(xiàn)了下面這種方式。

不再是逐條獲取驅(qū)動表的數(shù)據(jù),而是一塊一塊的獲取,引入join buffer 緩沖區(qū), 將驅(qū)動表join 相關(guān)的部分?jǐn)?shù)據(jù)列(大小受join buffer的限制)緩存到 join buffer中,然后開始掃描被驅(qū)動表,被驅(qū)動表的每一條記錄一次性和join buffer中所有的驅(qū)動表記錄進行匹配(內(nèi)存中操作)。將簡單嵌套循環(huán)中的多次比較合并成一次,降低了備驅(qū)動表的訪問頻率。

這里緩存的不只是關(guān)聯(lián)表的列,select后面的列也會緩存起來。所以查詢的時候盡量減少不必要的字段,可以讓join buffer中可以存放更多的列。

join_buffer_size的最大值在32為系統(tǒng)中可以申請4G,在64為操作系統(tǒng)中可以申請大于4G的空間。

MySQL對于被驅(qū)動表的關(guān)聯(lián)字段沒索引的關(guān)聯(lián)查詢,一般都會使用 BNL 算法。如果有索引一般選擇 NLJ 算法,有 索引的情況下 NLJ 算法比 BNL算法性能更高。

關(guān)聯(lián)查詢優(yōu)化總結(jié)

超過三個表禁止 join。【阿里巴巴JAVA開發(fā)手冊】

需要 join 的字段,數(shù)據(jù)類型必須絕對一致;【阿里巴巴JAVA開發(fā)手冊】

多表關(guān)聯(lián)查詢時,保證被關(guān)聯(lián)的字段需要有索引,盡量選擇NLJ算法?!景⒗锇桶蚃AVA開發(fā)手冊】

小表驅(qū)動大表,寫多表連接sql時如果明確知道哪張表是小表可以用straight_join寫法固定連接驅(qū)動方式,省去mysql優(yōu)化器自己判斷的時間

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MySQL數(shù)據(jù)類型詳解

    MySQL數(shù)據(jù)類型詳解

    本文詳細(xì)給大家介紹了MySQL數(shù)據(jù)類型的相關(guān)知識,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-10-10
  • MySQL按時間拆分千萬級大表的實現(xiàn)代碼

    MySQL按時間拆分千萬級大表的實現(xiàn)代碼

    這篇文章主要介紹了MySQL按時間拆分千萬級大表,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • MySQL事務(wù)的四種特性總結(jié)

    MySQL事務(wù)的四種特性總結(jié)

    事務(wù)就是一組DML語句組成,這些語句在邏輯上存在相關(guān)性,這一組DML語句要么全部成功,要么全部失敗,是一個整體,一個 MySQL 數(shù)據(jù)庫,可不止你一個事務(wù)在運行,所以一個完整的事務(wù),絕對不是簡單的 sql 集合,本文就給大家總結(jié)一下MySQL事務(wù)的四種特性
    2023-08-08
  • 怎樣正確創(chuàng)建MySQL索引的方法詳解

    怎樣正確創(chuàng)建MySQL索引的方法詳解

    今天小編就為大家分享一篇關(guān)于怎樣正確創(chuàng)建MySQL索引的方法詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Mysql5.6忘記root密碼修改root密碼的方法

    Mysql5.6忘記root密碼修改root密碼的方法

    這篇文章主要介紹了Mysql5.6忘記root密碼修改root密碼的方法的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • MySQL中一條update語句是如何執(zhí)行的

    MySQL中一條update語句是如何執(zhí)行的

    這篇文章主要給大家介紹了關(guān)于MySQL中一條update語句是如何執(zhí)行的相關(guān)資料,由于update涉及到數(shù)據(jù)的修改,所以很容易推斷,update語句比select語句會更復(fù)雜一些,需要的朋友可以參考下
    2022-03-03
  • MySQL通過DQL實現(xiàn)對數(shù)據(jù)庫數(shù)據(jù)的基本查詢

    MySQL通過DQL實現(xiàn)對數(shù)據(jù)庫數(shù)據(jù)的基本查詢

    這篇文章給大家介紹了MySQL如何通過DQL進行數(shù)據(jù)庫數(shù)據(jù)的基本查詢,文中通過代碼示例和圖文結(jié)合介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-01-01
  • MySQL更新,刪除操作分享

    MySQL更新,刪除操作分享

    這篇文章主要介紹了MySQL更新,刪除操作分享,文章根據(jù)MySQL的更新刪除命令的相關(guān)資料展開詳細(xì)的介紹,需要的小伙伴可以參考一下,希望對你有所幫助
    2022-03-03
  • centos7下安裝mysql的教程

    centos7下安裝mysql的教程

    這篇文章主要介紹了centos7安裝mysql的教程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-04-04
  • mysql中的group?by和between用法詳解

    mysql中的group?by和between用法詳解

    MySQL中的GROUP BY是數(shù)據(jù)聚合分析的核心功能,主要用于將結(jié)果集按指定列分組,并結(jié)合聚合函數(shù)進行統(tǒng)計計算,本文給大家介紹mysql中的group?by高級用法詳解,感興趣的朋友一起看看吧
    2025-05-05

最新評論

靖江市| 江津市| 栾城县| 兴安盟| 临安市| 通江县| 中卫市| 阿拉善盟| 邛崃市| 曲阜市| 肥西县| 滨海县| 玉田县| 吐鲁番市| 文安县| 汤阴县| 锡林浩特市| 石楼县| 陵水| 永年县| 佛山市| 丰台区| 仁化县| 库伦旗| 英德市| 黄大仙区| 达日县| 元阳县| 乌兰察布市| 和硕县| 盘山县| 方城县| 安多县| 普兰店市| 祁东县| 保山市| 北京市| 大同县| 赤峰市| 黄山市| 日照市|