mysql 聯(lián)接查詢算法之Block Nested-Loop Join(BNL) 二

Block Nested-Loop Join:BNLJ,緩存塊嵌套循環(huán)連接;

掃描一個(gè)表的過(guò)程其實(shí)是先把這個(gè)表從磁盤上加載到內(nèi)存中遏弱,然后從內(nèi)存中比較匹配條件是否滿足。但內(nèi)存里可能并不能完全存放的下表中所有的記錄衙四,所以在掃描表前邊記錄的時(shí)候后邊的記錄可能還在磁盤上液样,等掃描到后邊記錄的時(shí)候可能內(nèi)存不足呢堰,所以需要把前邊的記錄從內(nèi)存中釋放掉搓彻。我們前邊又說(shuō)過(guò)凛篙,采用SNLJ 算法的兩表聯(lián)接過(guò)程中峦甩,被驅(qū)動(dòng)表可是要被訪問(wèn)好多次的赘来。被驅(qū)動(dòng)表具體的訪問(wèn)次數(shù)就是由驅(qū)動(dòng)表返回結(jié)果集記錄數(shù)決定!如果這個(gè)被驅(qū)動(dòng)表中的數(shù)據(jù)特別多而且不能使用索引進(jìn)行訪問(wèn)凯傲,那就相當(dāng)于要從磁盤上讀好幾次這個(gè)表犬辰,這個(gè)I/O代價(jià)就非常大了,所以我們得想辦法:

盡量減少訪問(wèn)被驅(qū)動(dòng)表的次數(shù)冰单。 可以讓被驅(qū)動(dòng)表盡量的谢戏臁(小表驅(qū)動(dòng)大表思想!)

當(dāng)被驅(qū)動(dòng)表中的數(shù)據(jù)非常多時(shí)诫欠,每次訪問(wèn)被驅(qū)動(dòng)表涵卵,被驅(qū)動(dòng)表的記錄會(huì)被加載到內(nèi)存中浴栽,在內(nèi)存中的每一條記錄只會(huì)和驅(qū)動(dòng)表結(jié)果集的一條記錄做匹配,之后就會(huì)被從內(nèi)存中清除掉缘厢。然后再?gòu)尿?qū)動(dòng)表結(jié)果集中拿出另一條記錄吃度,再一次把被驅(qū)動(dòng)表的記錄加載到內(nèi)存中一遍,周而復(fù)始贴硫,驅(qū)動(dòng)表結(jié)果集中有多少條記錄椿每,就得把被驅(qū)動(dòng)表從磁盤上加載到內(nèi)存中多少次。

所以我們可不可以在把被驅(qū)動(dòng)表的記錄加載到內(nèi)存的時(shí)候英遭,一次性和多條驅(qū)動(dòng)表中的記錄做匹配间护,這樣就可以大大減少重復(fù)從磁盤上加載被驅(qū)動(dòng)表的代價(jià)了。這也就是Block Nested-Loop Join算法的思想挖诸。

也就是說(shuō)在有索引的情況下汁尺,MySQL會(huì)嘗試去使用Index Nested-Loop Join算法,在有些情況下多律,可能Join的列就是沒(méi)有索引痴突,那么這時(shí)MySQL的選擇絕對(duì)不會(huì)是最先介紹的Simple Nested-Loop Join算法,SNLJ算法是最慢的join狼荞,畢竟是笛卡爾積辽装!

而Block Nested-Loop Join算法較Simple Nested-Loop Join的改進(jìn)就在于可以減少內(nèi)表的掃描次數(shù),甚至可以和Hash Join算法一樣相味,僅需掃描內(nèi)表一次拾积。其使用Join Buffer(聯(lián)接緩沖)來(lái)減少內(nèi)部循環(huán)讀取表的次數(shù)。
關(guān)于 join buffer http://www.reibang.com/p/3c0816862cc9

For each tuple r in R do                             -- 掃描外表R
    store used columns as p from R in Join Buffer    -- 將部分或者全部R的記錄保存到Join Buffer中丰涉,記為p
    For each tuple s in S do                         -- 掃描內(nèi)表S
        If p and s satisfy the join condition        -- p與s滿足join條件
            Then output the tuple                    -- 返回為結(jié)果集

可以看到相比Simple Nested-Loop Join算法拓巧,Block Nested-LoopJoin算法僅多了一個(gè)所謂的Join Buffer,為什么這樣就能減少內(nèi)表的掃描次數(shù)呢一死?下圖相比更好地解釋了Block Nested-Loop Join算法的運(yùn)行過(guò)程:


image

可以看到Join Buffer用以緩存聯(lián)接需要的列(所以再次提醒我們肛度,最好不要把*作為查詢列表,只需要把我們關(guān)心的列放到查詢列表就好了投慈,這樣還可以在join buffer中放置更多的記錄呢)贤斜,然后以Join Buffer批量的形式和內(nèi)表中的數(shù)據(jù)進(jìn)行聯(lián)接比較。就上圖來(lái)看逛裤,記錄r1瘩绒,r2 … rT的聯(lián)接僅需掃內(nèi)表一次,如果join buffer可以緩存所有的外表列带族,那么聯(lián)接僅需掃描內(nèi)外表各一次锁荔,從而大幅提升Join的性能。
Block Nested-Loop Join開銷

Block Nested-Loop Join極大的避免了內(nèi)表的掃描次數(shù)蝙砌,如果Join Buffer可以緩存外表的數(shù)據(jù)阳堕,那么內(nèi)表的掃描僅需一次跋理,這和Hash Join非常類似。但是Block Nested-Loop Join依然沒(méi)有解決的是Join比較的次數(shù)恬总,其仍然通過(guò)Join判斷式進(jìn)行比較前普。綜上所述,到目前為止各Join算法的成本比較如下所示:


image.png

Block Nested-Loop Join影響

在使用 Block Nested-Loop Join(BNL) 算法時(shí)壹堰,還是可能會(huì)對(duì)被驅(qū)動(dòng)表做多次掃描(盡管可能已經(jīng)將驅(qū)動(dòng)表中大部分關(guān)聯(lián)字段數(shù)據(jù)存入join buffer)拭卿。如果這個(gè)被驅(qū)動(dòng)表是一個(gè)大的冷數(shù)據(jù)表,除了會(huì)導(dǎo)致 IO 壓力大以外贱纠,還會(huì)對(duì) buffer pool產(chǎn)生嚴(yán)重的影響峻厚!

如果了解 InnoDB 的 LRU 算法就會(huì)知道,由于 InnoDB 對(duì) Bufffer Pool 的 LRU 算法做了優(yōu)化谆焊,即:第一次從磁盤讀入內(nèi)存的數(shù)據(jù)頁(yè)惠桃,會(huì)先放在 old 區(qū)域。如果 1 秒之后這個(gè)數(shù)據(jù)頁(yè)不再被訪問(wèn)了辖试,就不會(huì)被移動(dòng)到 LRU 鏈表頭部辜王,這樣對(duì) Buffer Pool 的命中率影響就不大。

但是罐孝,如果一個(gè)使用 BNL 算法的 join 語(yǔ)句誓禁,多次掃描一個(gè)冷表,而且這個(gè)語(yǔ)句執(zhí)行時(shí)間超過(guò) 1 秒肾档,就會(huì)在再次掃描冷表的時(shí)候,把冷表的數(shù)據(jù)頁(yè)移到 LRU 鏈表頭部辫继。這種情況對(duì)應(yīng)的怒见,是冷表的數(shù)據(jù)量小于整個(gè) Buffer Pool 的 3/8,能夠完全放入 old 區(qū)域的情況姑宽。如果這個(gè)冷表很大遣耍,就會(huì)出現(xiàn)另外一種情況:業(yè)務(wù)正常訪問(wèn)的數(shù)據(jù)頁(yè),沒(méi)有機(jī)會(huì)進(jìn)入 young 區(qū)域炮车。(導(dǎo)致正常業(yè)務(wù)sql查詢因?yàn)闆](méi)有剩余buffer pool空間進(jìn)一步讓磁盤IO變多而變得緩慢)

由于優(yōu)化機(jī)制的存在舵变,一個(gè)正常訪問(wèn)的數(shù)據(jù)頁(yè),要進(jìn)入 young 區(qū)域瘦穆,需要隔 1 秒后再次被訪問(wèn)到纪隙。但是,由于我們的 join 語(yǔ)句在循環(huán)讀磁盤和淘汰內(nèi)存頁(yè)扛或,進(jìn)入 old 區(qū)域的數(shù)據(jù)頁(yè)绵咱,很可能在 1 秒之內(nèi)就被淘汰了。這樣熙兔,就會(huì)導(dǎo)致這個(gè) MySQL 實(shí)例的 Buffer Pool 在這段時(shí)間內(nèi)悲伶,young 區(qū)域的數(shù)據(jù)頁(yè)沒(méi)有被合理地淘汰艾恼。

也就是說(shuō),這兩種情況都會(huì)影響 Buffer Pool 的正常運(yùn)作麸锉。 大表 join 操作雖然對(duì) IO 有影響钠绍,但是在語(yǔ)句執(zhí)行結(jié)束后,對(duì) IO 的影響也就結(jié)束了花沉。但是柳爽,對(duì) Buffer Pool 的影響就是持續(xù)性的,需要依靠后續(xù)的查詢請(qǐng)求慢慢恢復(fù)內(nèi)存命中率主穗。

為了減少這種影響泻拦,你可以考慮增大 join_buffer_size 的值,減少對(duì)被驅(qū)動(dòng)表的掃描次數(shù)!
也就是說(shuō)忽媒,BNL 算法對(duì)系統(tǒng)的影響主要包括三個(gè)方面: 可能會(huì)多次掃描被驅(qū)動(dòng)表争拐,占用磁盤 IO 資源; 判斷 join 條件需要執(zhí)行 M*N 次對(duì)比(M晦雨、N 分別是兩張表的行數(shù))架曹,如果是大表就會(huì)占用非常多的 CPU 資源; 可能會(huì)導(dǎo)致 Buffer Pool 的熱數(shù)據(jù)被淘汰闹瞧,影響內(nèi)存命中率绑雄。

那么假設(shè)被驅(qū)動(dòng)表全在內(nèi)存中,這個(gè)時(shí)候 SNLJ 和 BNL 算法還有性能差別嗎奥邮?當(dāng)然是有的万牺,由于 SNLJ 這個(gè)算法天然會(huì)對(duì)被驅(qū)動(dòng)表的數(shù)據(jù)做多次訪問(wèn),所以更容易將這些數(shù)據(jù)頁(yè)放到 Buffer Pool 的頭部洽腺,從而污染 Buffer Pool脚粟。另外,即使被驅(qū)動(dòng)表數(shù)據(jù)都在內(nèi)存中蘸朋,但每次查找“下一個(gè)記錄的操作”核无,都是類似指針操作。而 BNL 算法中的 join_buffer 是數(shù)組藕坯,遍歷的成本更低团南,從被驅(qū)動(dòng)表讀取一條數(shù)據(jù)去 join_buffer 中遍歷。

BNL的相關(guān)設(shè)置
mysql默認(rèn)開啟BNL

SHOW VARIABLES LIKE '%optimizer_switch%'

index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on

開關(guān)BNL

SET optimizer_switch = 'block_nested_loop=on'; 
SET optimizer_switch = 'block_nested_loop=off'; 

總結(jié)下

1炼彪、 緩存塊嵌套循環(huán)連接通過(guò)一次性緩存多條數(shù)據(jù)吐根,把參與查詢的列緩存到Join Buffer 里,然后拿join buffer里的數(shù)據(jù)批量與內(nèi)層表的數(shù)據(jù)進(jìn)行匹配辐马,從而減少了內(nèi)層循環(huán)的次數(shù)佑惠、減少了內(nèi)部表訪問(wèn)次數(shù)(遍歷一次內(nèi)層表就可以批量匹配一次Join Buffer里面的外層表數(shù)據(jù))。
2、什么時(shí)候會(huì)使用BNL? 當(dāng)內(nèi)表關(guān)聯(lián)字段上沒(méi)有索引時(shí)膜楷,不使用Index Nested-Loop Join的時(shí)候旭咽,默認(rèn)使用Block Nested-Loop Join。
3赌厅、join buffer的相關(guān)概念:
待續(xù)穷绵。。特愿。仲墨。。
4揍障、使用Block Nested-Loop Join算法需要開啟優(yōu)化器管理配置的optimizer_switch的設(shè)置block_nested_loop為on目养,默認(rèn)為開啟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末毒嫡,一起剝皮案震驚了整個(gè)濱河市癌蚁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌兜畸,老刑警劉巖努释,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異咬摇,居然都是意外死亡伐蒂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門肛鹏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)逸邦,“玉大人,你說(shuō)我怎么就攤上這事在扰÷萍酰” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵健田,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我佛纫,道長(zhǎng)妓局,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任呈宇,我火速辦了婚禮好爬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甥啄。我一直安慰自己存炮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著穆桂,像睡著了一般宫盔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上享完,一...
    開封第一講書人閱讀 51,610評(píng)論 1 305
  • 那天灼芭,我揣著相機(jī)與錄音,去河邊找鬼般又。 笑死彼绷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茴迁。 我是一名探鬼主播寄悯,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼堕义!你這毒婦竟也來(lái)了猜旬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤胳螟,失蹤者是張志新(化名)和其女友劉穎昔馋,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體糖耸,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秘遏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嘉竟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邦危。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖舍扰,靈堂內(nèi)的尸體忽然破棺而出倦蚪,到底是詐尸還是另有隱情,我是刑警寧澤边苹,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布陵且,位于F島的核電站,受9級(jí)特大地震影響个束,放射性物質(zhì)發(fā)生泄漏慕购。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一茬底、第九天 我趴在偏房一處隱蔽的房頂上張望沪悲。 院中可真熱鬧,春花似錦阱表、人聲如沸殿如。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涉馁。三九已至门岔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谨胞,已是汗流浹背固歪。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胯努,地道東北人牢裳。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像叶沛,于是被迫代替她去往敵國(guó)和親蒲讯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 概述 相信有開發(fā)或DBA小伙伴,對(duì)于mysql處理多表關(guān)聯(lián)方式或者說(shuō)性能方面一直不太滿意,對(duì)于開發(fā)提交的join查...
    Sunny捏閱讀 790評(píng)論 0 0
  • 一灰署、join的優(yōu)化: 1判帮、Multi-Range Read(MRR)優(yōu)化回表操作: 對(duì)于語(yǔ)句: <1>、優(yōu)化前: ...
    墨殤染淚閱讀 607評(píng)論 1 1
  • 一溉箕、數(shù)據(jù)庫(kù)的 join 查詢 數(shù)據(jù)庫(kù)提供了多種類型的連接方式晦墙,它們之間的區(qū)別在于:從相互交疊的不同數(shù)據(jù)集合中選擇用...
    Djbfifjd閱讀 1,850評(píng)論 0 13
  • Simple Nested-Loop Join:SNLJ,簡(jiǎn)單嵌套循環(huán)連接 Simple Nested-Loops...
    尹楷楷閱讀 1,502評(píng)論 0 1
  • 久違的晴天肴茄,家長(zhǎng)會(huì)晌畅。 家長(zhǎng)大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒(méi)多少時(shí)間了寡痰。班主任說(shuō)已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)抗楔。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評(píng)論 16 22