MySQL系列之Join大法

1.?Index Nested-Loop Join

概念解釋:

假設(shè)有t1,t2兩張表吃环,在join連接的時(shí)候计露,t1表驅(qū)動(dòng)t2表,t1走的全部掃描饲嗽,t2表使用了索引,

則這個(gè)時(shí)候join就使用了“index nested-loop join”算法奈嘿,簡(jiǎn)稱:NLJ貌虾。

NLJ執(zhí)行的流程如下:


Index Nested-Loop Join 算法的執(zhí)行流程

2.?Block Nested-Loop Join

基于上面t1表和t2表,join連接裙犹,t1表和t2表都沒(méi)有命中索引尽狠,都是走的全部掃描。這個(gè)

時(shí)候Join使用的是“Block Nested-Loop Join”算法叶圃,簡(jiǎn)稱:BNL袄膏。

BNL算法的流程如下:


Block Nested-Loop Join 算法的執(zhí)行流程


在explain分析語(yǔ)句的時(shí)候,extra附加信息中會(huì)出現(xiàn)“Using join buffer (Block Nested Loop)”掺冠。

join_buffer是由參數(shù)join_buffer_size決定的沉馆。默認(rèn)是256k。如果放不下表 t1

的所有數(shù)據(jù)話德崭,策略很簡(jiǎn)單斥黑,就是分段放。

流程大概是:

取t1表的數(shù)據(jù)眉厨,放入join_buffer中锌奴,如果join buffer滿了,就掃描t2表的數(shù)據(jù)缺猛,跟join buffer

的數(shù)據(jù)進(jìn)行對(duì)比缨叫,滿足join條件的作為結(jié)果集返回;清空join buffer荔燎,繼續(xù)上面的過(guò)程耻姥。

能否使用Join?

1.?如果可以使用 Index Nested-Loop Join 算法有咨,也就是說(shuō)可以用上被驅(qū)動(dòng)表上的索引琐簇,

其實(shí)是沒(méi)問(wèn)題的;

2.? 如果使用 Block Nested-Loop Join 算法,掃描行數(shù)就會(huì)過(guò)多婉商。尤其是在大表上的 join

操作似忧,這樣可能要掃描被驅(qū)動(dòng)表很多次,會(huì)占用大量的系統(tǒng)資源丈秩。所以這種 join 盡量不

要用盯捌。

如果要使用 join,應(yīng)該選擇大表做驅(qū)動(dòng)表還是選擇小表做驅(qū)動(dòng)表蘑秽?

1. 如果是 Index Nested-Loop Join 算法饺著,應(yīng)該選擇小表做驅(qū)動(dòng)表;

2.?如果是 Block Nested-Loop Join 算法:

? ??在 join_buffer_size 足夠大的時(shí)候肠牲,是一樣的幼衰;

? ??在 join_buffer_size 不夠大的時(shí)候(這種情況更常見(jiàn)),應(yīng)該選擇小表做驅(qū)動(dòng)表缀雳。

????這個(gè)問(wèn)題的結(jié)論就是渡嚣,總是應(yīng)該使用小表做驅(qū)動(dòng)表。

注意:join慢的時(shí)候肥印,盡量跳大join_buffer_size的值识椰。

優(yōu)化Join

1. 優(yōu)化NLJ算法

Multi-Range Read 優(yōu)化算法 (MRR)。這個(gè)優(yōu)化的主要目的是盡量使用順序讀盤竖独。

如果隨著輔助索引(二級(jí)索引) a 的值遞增順序查詢的話裤唠,主鍵索引id 的值就變成隨機(jī)的挤牛,

那么就會(huì)出現(xiàn)隨機(jī)訪問(wèn)莹痢,性能相對(duì)較差。雖然“按行查”這個(gè)機(jī)制不能改墓赴,但是調(diào)整查詢的順序竞膳,

還是能夠加速的。這就是 MRR 優(yōu)化的設(shè)計(jì)思路诫硕。

加入了MRR優(yōu)化的執(zhí)行流程如下:

1. 根據(jù)索引 a坦辟,定位到滿足條件的記錄,將 id 值放入 read_rnd_buffer 中 ;

2.?將 read_rnd_buffer 中的 id 進(jìn)行遞增排序章办;

3. 排序后的 id 數(shù)組锉走,依次到主鍵 id 索引中查記錄,并作為結(jié)果返回藕届。

read_rnd_buffer 的大小是由 read_rnd_buffer_size 參數(shù)控制的挪蹭。

啟用MRR算法:

set optimizer_switch="mrr_cost_based=off"

Batched Key Access (BKA) 算法

MySQL 在 5.6 引入的,是對(duì) NLJ 算法的優(yōu)化休偶。

NLJ 算法優(yōu)化后的 BKA 算法的流程如下:


Batched Key Acess 流程

啟用 BKA 算法:

set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

前兩個(gè)參數(shù)的作用是要啟用 MRR梁厉。這么做的原因是,BKA 算法的優(yōu)化要依賴于MRR踏兜。

BNL 算法的優(yōu)化

優(yōu)化的常見(jiàn)做法是词顾,給被驅(qū)動(dòng)表的 join 字段加上索引八秃,把 BNL 算法轉(zhuǎn)成 BKA 算法。

但是如果無(wú)法在被驅(qū)動(dòng)表上加索引肉盹,那么:

考慮使用臨時(shí)表昔驱,使用臨時(shí)表的大致思路是:

1. 把表 t2 中滿足條件的數(shù)據(jù)放在臨時(shí)表 tmp_t 中;

2. 為了讓 join 使用 BKA 算法上忍,給臨時(shí)表 tmp_t 的字段 b 加上索引舍悯;

3. 讓表 t1 和 tmp_t 做 join 操作。

SQL語(yǔ)句為:

create temporary table temp_t(id int primary key, a int, b int, index(b))engine=innodb;

insert into temp_t select * from t2 where b>=1 and b<=2000;

select * from t1 join temp_t on (t1.b=temp_t.b);

總體來(lái)看睡雇,不論是在原表上加索引萌衬,還是用有索引的臨時(shí)表,我們的思路都是讓 join 語(yǔ)句

能夠用上被驅(qū)動(dòng)表上的索引它抱,來(lái)觸發(fā) BKA 算法秕豫,提升查詢性能。

上面如果不適用臨時(shí)表進(jìn)行優(yōu)化观蓄,那么還有其他方式進(jìn)行優(yōu)化混移?

我們可以自己實(shí)現(xiàn)在業(yè)務(wù)端。實(shí)現(xiàn)流程大致如下:

1. select * from t1;取得表 t1 的全部 1000 行數(shù)據(jù)侮穿,在業(yè)務(wù)端存入一個(gè) hash 結(jié)構(gòu)歌径,

比如 C++ 里的 set、PHP 的數(shù)組這樣的數(shù)據(jù)結(jié)構(gòu)亲茅。

2. select * from t2 where b>=1 and b<=2000; 獲取表 t2 中滿足條件的 2000 行

數(shù)據(jù)回铛。

3. 把這 2000 行數(shù)據(jù),一行一行地取到業(yè)務(wù)端克锣,到 hash 結(jié)構(gòu)的數(shù)據(jù)表中尋找匹配的數(shù)

據(jù)茵肃。滿足匹配的條件的這行數(shù)據(jù),就作為結(jié)果集的一行袭祟。

關(guān)于臨時(shí)表的幾個(gè)問(wèn)題:

1.? binlog_format=row验残,那么跟臨時(shí)表有關(guān)的語(yǔ)句,就不會(huì)記錄到binlog 里巾乳。只在?

binlog_format=statment/mixed 的時(shí)候您没,binlog 中才會(huì)記錄臨時(shí)表的操作。

2. 在使用臨時(shí)表的時(shí)候胆绊,最后最好要寫上 DROP TEMPORARY TABLE氨鹏,刪除臨時(shí)表

3. 臨時(shí)表只對(duì)本session會(huì)話可見(jiàn),對(duì)其他的session不可見(jiàn)辑舷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末喻犁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肢础,老刑警劉巖还栓,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異传轰,居然都是意外死亡剩盒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門慨蛙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辽聊,“玉大人,你說(shuō)我怎么就攤上這事期贫「遥” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵通砍,是天一觀的道長(zhǎng)玛臂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)封孙,這世上最難降的妖魔是什么迹冤? 我笑而不...
    開(kāi)封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮虎忌,結(jié)果婚禮上泡徙,老公的妹妹穿的比我還像新娘。我一直安慰自己膜蠢,他們只是感情好堪藐,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著狡蝶,像睡著了一般庶橱。 火紅的嫁衣襯著肌膚如雪贮勃。 梳的紋絲不亂的頭發(fā)上贪惹,一...
    開(kāi)封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音寂嘉,去河邊找鬼奏瞬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泉孩,可吹牛的內(nèi)容都是我干的硼端。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼寓搬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼珍昨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镣典,失蹤者是張志新(化名)和其女友劉穎兔毙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體兄春,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡澎剥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赶舆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哑姚。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖芜茵,靈堂內(nèi)的尸體忽然破棺而出叙量,到底是詐尸還是另有隱情,我是刑警寧澤九串,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布宛乃,位于F島的核電站,受9級(jí)特大地震影響蒸辆,放射性物質(zhì)發(fā)生泄漏征炼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一躬贡、第九天 我趴在偏房一處隱蔽的房頂上張望谆奥。 院中可真熱鬧,春花似錦拂玻、人聲如沸酸些。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)魄懂。三九已至,卻和暖如春闯第,著一層夾襖步出監(jiān)牢的瞬間市栗,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工咳短, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留填帽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓咙好,卻偏偏與公主長(zhǎng)得像篡腌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子勾效,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359