mysql的join算法_mysql的Join算法-阿里云开发者社区
實(shí)為吾之愚見,望諸君酌之!聞過則喜,與君共勉
測試數(shù)據(jù)
CREATE TABLE `dept_emp` (
`emp_no` int(11) NOT NULL,
`dept_no` char(4) NOT NULL,
`from_date` date NOT NULL,
`to_date` date NOT NULL,
PRIMARY KEY (`emp_no`,`dept_no`),
KEY
`from_date` (`from_date`),
CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES
`employees` (`emp_no`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1
CREATE TABLE `departments` (
`dept_no` char(4) NOT NULL,
`dept_name` varchar(40) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
mysql> select count(1) from departments;
+----------+
| count(1) |
+----------+
|
9 |
+----------+
1 row in set (0.00 sec)
mysql> select count(1) from dept_emp;
+----------+
| count(1) |
+----------+
|
331603 |
+----------+
1 row in set (0.08 sec)
其中dept_emp有331603行記錄,departments有9行數(shù)據(jù)
事例查詢
select e.to_date,d.dept_name from dept_emp
e,departments d where e.dept_no=d.dept_no;
這是一個(gè)兩表join的query,對應(yīng)條件是where e.dept_no=d.dept_no,主要找出表dept_emp和departments中,滿足dept_no相等的記錄,然后展示出e.to_date,d.dept_name列其中dept_emp有331603行記錄,departments有9行數(shù)據(jù)
執(zhí)行計(jì)劃對比
關(guān)閉block_nested_loop
打開block_nested_loop
打開batched_key_access
Nested-Loop事例
Nested-Loop Join
關(guān)閉設(shè)置optimizer_switch的block_nested_loop為off,然后查看查詢的執(zhí)行計(jì)劃
從上圖可知,執(zhí)行計(jì)劃對departments是全表掃描(9行數(shù)據(jù)),對dept_emp也是全表掃描(331570行數(shù)據(jù)),當(dāng)使用Nested-Loop Join算法的時(shí)候,先逐行的讀取departments表(此處是全表掃描,僅限于該sql),針對departments的每一行數(shù)據(jù),都對表dept_emp的每一行記錄進(jìn)行匹配(此處是全表掃描,僅限于該sql)滿足條件的行(where e.dept_no=d.dept_no),wiki的偽代碼如下:
For each tuple r in R do
For each tuple s in S do
If r and s satisfy the join condition
Then output the tuple
過程概括如下圖:
上圖所示,departments的row1要和dept_emp每一行做條件匹配,查找符合條件的行,反復(fù)循環(huán),直至departments的記錄掃描完成(最后一條記錄rown與dept_emp的每一行都進(jìn)行了條件匹配)
Block_nested_loop
先打開設(shè)置optimizer_switch的block_nested_loop為on,然后查看查詢的執(zhí)行計(jì)劃
從上圖可知,執(zhí)行計(jì)劃對departments是全表掃描(9行數(shù)據(jù)),對dept_emp也是全表掃描(331570行數(shù)據(jù)),但是extra列多了一部分” Using join buffer (Block Nested Loop)”,當(dāng)使用Block
Nested-Loop Join算法的時(shí)候,先逐行的讀取departments表(此處是全表掃描,僅限于該sql),然后把讀取的數(shù)據(jù),存儲到j(luò)oin buffer里(如果join buffer足夠大,就可以一次全部存儲departments所需要的join對象了,如果join buffer太小,一次只可以緩存departments的一部分join對象的話,就需要分多次進(jìn)行緩存departments的join對象),針對join buffer中緩存的數(shù)據(jù)(注意之前的一次緩存以及多次緩存),批量(不需要與Nested-Loop Join一樣,一條條的比較了,可以多條比較了)的對表dept_emp的每一行記錄進(jìn)行匹配(此處是全表掃描,僅限于該sql)滿足條件的行(where e.dept_no=d.dept_no),偽代碼可以寫成(參考的wiki):
For each tuple r in R do
store used columns from R in join buffer
For each tuple s in S do
If r and s satisfy the join condition
Then output the tuple
過程概括如下圖:
當(dāng)為dept_emp表的列dept_no添加一個(gè)索引的時(shí)候(二級索引,已經(jīng)有主鍵索引),再觀察執(zhí)行計(jì)劃:
Join type從all變成了ref,可以理解為對dept_emp執(zhí)行join的時(shí)候,使用索引進(jìn)行匹配(對應(yīng)之前的全表掃描),這里預(yù)估的行數(shù)是20723rows,比之前的331570rows少了很多(全表掃描),執(zhí)行計(jì)劃從全表掃描和ref(join type)中,選擇了
ref,對比之前的block_nested_loop,過程變化如下:
由于dept_emp下的dept_no是二級索引,查詢中又查詢了e.to_date(單單從二級索引里獲取不到數(shù)據(jù)),于是需要通過索引,查詢表里面對應(yīng)的e.to_date的值,這是如上圖可知,訪問時(shí)隨機(jī)的(圖例的表現(xiàn)方式是row1對應(yīng)pk2,row2對應(yīng)pk1等等),可能會產(chǎn)生隨機(jī)io,如果不查詢e.to_date,則不需要再去表里查詢了,同時(shí)Extra會顯示Using index,如下:
Batched_key_access
在Block_nested_loop最后部分,使用二級索引查詢的時(shí)候,出現(xiàn)了一個(gè)現(xiàn)象:當(dāng)獲取的數(shù)據(jù)二級索引無法滿足時(shí),需要去查詢原始的數(shù)據(jù)表來確定數(shù)據(jù),查詢數(shù)據(jù)是通過主鍵去查的,會出現(xiàn)不是按照主鍵順序查的情況,如果有辦法把這些無序的主鍵查詢轉(zhuǎn)換成有序的去查詢表的數(shù)據(jù)(聚簇索引),會節(jié)省很多的時(shí)間,mysql提供了Batched_key_access算法來實(shí)現(xiàn)這個(gè)需求,復(fù)現(xiàn)如下:
對比之前的Block_nested_loop(有索引和沒有索引兩部分),上面加索引后,開啟了mrr,batched_key_access,同時(shí)關(guān)閉了mrr_cost_based,這個(gè)時(shí)候Extra列出現(xiàn)了Using join buffer (Batched Key Access),使用Batched_key_access的過程如下:
上圖看,join buffer會緩存departments相關(guān)的join列,Batched_key_access算法會使用dept_no二級索引去查找,由于是無序的,查找前把這些key(可以大概理解為主鍵信息+join buffer里行的標(biāo)識信息)的信息反饋給mrr 去,mrr會按照主鍵(沒有主鍵使用row id)排序,然后順序的去dept_emp里去查找信息,并發(fā)信息再次反饋給Batched_key_access算法去和join buffer里的row進(jìn)行比較
總結(jié)
以上是生活随笔為你收集整理的mysql的join算法_mysql的Join算法-阿里云开发者社区的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oa办公自动化系统(ssh mysql)
- 下一篇: junit链接mysql_java –