MySql系列(三) JOIN的原理和演算法

2021-09-22 01:33:23 字數 4404 閱讀 3275

博主今天為大家帶來join的原理,只有少部分,有待補充提高,如有更好地建議,歡飲討論!

以下所寫內容均與以前的文章有聯絡可以前往博文檢視,陳永佳的部落格

什麼是join?

join的含義就如英文單詞「join」一樣,連線兩張表,大致分為內連線,外連線,右連線,左連線,自然連線。這裡描述先甩出一張用爛了的圖,然後插入測試資料。

笛卡爾積:cross join

要理解各種join首先要理解笛卡爾積。笛卡爾積就是將a表的每一條記錄與b表的每一條記錄強行拼在一起。所以,如果a表有n條記錄,b表有m條記錄,笛卡爾積產生的結果就會產生n*m條記錄。

建表:(想查詢先建表)

create database db0206;

use db0206;

create table `db0206`.`tbl_dept`(

`id` int(11) not null auto_increment,

`deptname` varchar(30),

`locadd` varchar(40),

primary key (`id`)

) engine=innodb charset=utf8mb4;

create table `db0206`.`tbl_emp`(

`id` int(11) not null auto_increment,

`name` varchar(20),

`deptid` int(11),

primary key (`id`),

foreign key (`deptid`) references `db0206`.`tb_dept`(`id`)

) engine=innodb charset=utf8mb4;

/*插入資料*/

insert into tbl_dept(deptname,locadd) values('cc',21);

insert into tbl_dept(deptname,locadd) values('mm',21);

insert into tbl_dept(deptname,locadd) values('sc',22);

insert into tbl_dept(deptname,locadd) values('sc',23);

insert into tbl_dept(deptname,locadd) values('eh',65);

insert into tbl_emp(name,deptid) values('c1',1);

insert into tbl_emp(name,deptid) values('c2',1);

insert into tbl_emp(name,deptid) values('c3',1);

insert into tbl_emp(name,deptid) values('m5',2);

insert into tbl_emp(name,deptid) values('m6',2);

insert into tbl_emp(name,deptid) values('s7',3);

insert into tbl_emp(name,deptid) values('s8',4);

下列查詢與該錶資料有異請自行忽略內連線:

左外連線:

右外連線:

左連線:

右連線:

全連線:

兩張表中都沒有出現的資料集:

nested loop join(nlj)演算法:

首先介紹一種基礎演算法:nlj,巢狀迴圈演算法。迴圈外層是驅動表,循壞內層是被驅動表。驅動表會驅動被驅動表進行連線操作。首先驅動表找到第一條記錄,然後從頭掃瞄被驅動表,逐一查詢與驅動表第一條記錄匹配的記錄然後連線起來形成結果表中的一條記。被驅動表查詢完後,再從驅動表中取出第二個記錄,然後從頭掃瞄被驅動表,逐一查詢與驅動表第二條記錄匹配的記錄,連線起來形成結果表中的一條記錄。重複上述操作,直到驅動表的全部記錄都處理完畢為止。這就是巢狀迴圈連線演算法的基本思想,偽**如下。

foreach row1 from t1

foreach row2 from t2

if row2 match row1 //row2與row1匹配,滿足連線條件

join row1 and row2 into result //連線row1和row2加入結果集

首先載入t1,然後從t1中取出第一條記錄,之後載入t2表,與t2表中的記錄逐個匹配,連線匹配的記錄。

block nested loop join(bnlj)演算法:

再介紹一種高階演算法:bnlj,塊巢狀迴圈演算法,可以看作對nlj的優化。大致思想就是建立乙個快取區,一次從驅動表中取多條記錄,然後掃瞄被驅動表,被驅動表的每一條記錄都嘗試與緩衝區中的多條記錄匹配,如果匹配則連線並加入結果集。緩衝區越大,驅動表一次取出的記錄就越多。這個演算法的優化思路就是減少內迴圈的次數從而提高表連線效率。(博主用的很少哈哈!)

影響效能的因素
1.內迴圈的次數:現在考慮這麼乙個場景,當t1有100條記錄,t2有10000條記錄。那麼,t1驅動t2與t2驅動t1,他們之間在效率上孰優孰劣?如果是單純的分析指令執行次數,他們都是100*10000,但是考慮到載入表的次數呢。首先分析t1驅動t2,t1表載入1次,t2表需要載入100次。然後分析t2驅動t1,t2表首先載入1次,但是t1表要載入10000次。所以,t1驅動t2的效率要優於t2驅動t1的效率。小表驅動大表能夠減少內迴圈的次數從而提高連線效率。另外,如果使用block nested loop join演算法的話,通過擴大一次快取區的大小也能減小內迴圈的次數。由此又可得,設定合理的緩衝區大小能夠提高連線效率

2.快速匹配:掃瞄被驅動表尋找合適的記錄可以看做乙個查詢操作,如何提高查詢的效率呢?建索引啊!由此還可得出,在被驅動表建立索引能夠提高連線效率

3.排序:假設t1表驅動t2表進行連線操作,連線條件是t1.id=t2.id,而且要求查詢結果對id排序。現在有兩種選擇,方式一[…order by t1.id],方式二[…order by t2.id]。如果我們使用方式一的話,可以先對t1進行排序然後執行表連線演算法,如果我們使用方式二的話,只能在執行表連線演算法後,對結果集進行排序(using temporary),效率自然低下。由此最後可得出,優先選擇驅動表的屬性進行排序能夠提高連線效率。

引用
《資料庫系統概論》:

5.6版本及以後,優化器管理引數optimizer_switch中中的block_nested_loop引數控制著bnl是否被用於優化器。預設條件下是開啟,若果設定為off,優化器在選擇 join方式的時候會選擇nlj演算法。

MySQL的JOIN(二) JOIN原理

nested loop join nlj 演算法 首先介紹一種基礎演算法 nlj,巢狀迴圈演算法。迴圈外層是驅動表,循壞內層是被驅動表。驅動表會驅動被驅動表進行連線操作。首先驅動表找到第一條記錄,然後從頭掃瞄被驅動表,逐一查詢與驅動表第一條記錄匹配的記錄然後連線起來形成結果表中的一條記。被驅動表查詢...

Mysql系列 Join多種用法

sql優化中常用的方法之一就是將表關聯或子查詢改為join的用法,如上圖所示join的用法有很多種,導致有很多小夥伴經常搞混。本文將通過具體例子介紹sql中的各種常用join的特性和使用。準備資料 create table tb1 ept id int 11 not null auto increm...

MySQL 33 join語句原理

現在有表t,r,表t有a,b欄位,表r有c,d欄位,a欄位和c欄位有建立索引,表t有100000行資料,表r有6行資料。我們先來普通的join語句,在join語句中,存在驅動表和被驅動表,mysql會已小表已用來驅動大表,小表就是資料量較小的那個。例如執行如下語句,我們就會看來是用表r驅動表t的 e...