日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

《DBNotes:Join算法的前世今生》

發(fā)布時(shí)間:2023/12/1 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《DBNotes:Join算法的前世今生》 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

  • NestLoopJoin算法
    • Simple Nested-Loop Join
    • Index Nested-Loop Join
    • Block Nested-Loop Join
    • Batched Key Access
  • Hash Join算法
    • In-Memory Join(CHJ)
    • On-Disk Hash Join
  • 參考鏈接

在8.0.18之前,MySQL只支持NestLoopJoin算法,最簡(jiǎn)單的就是Simple NestLoop Join,MySQL針對(duì)這個(gè)算法做了若干優(yōu)化,實(shí)現(xiàn)了Block NestLoop Join,Index NestLoop Join和Batched Key Access等,有了這些優(yōu)化,在一定程度上能緩解對(duì)HashJoin的迫切程度。但是HashJoin的支持使得MySQL優(yōu)化器有更多選擇,SQL的執(zhí)行路徑也能做到更優(yōu),尤其是對(duì)于等值join的場(chǎng)景。

NestLoopJoin算法

長(zhǎng)期以來(lái),在MySQL中執(zhí)行聯(lián)接的唯一算法是嵌套循環(huán)算法的變體。

Simple Nested-Loop Join

如果我們執(zhí)行這樣一條等值查詢語(yǔ)句:

select * from t1 straight_join t2 on (t1.a=t2.b);

由于表 t2 的字段 b 上沒(méi)有索引,每次到 t2 去匹配的時(shí)候,就要做一次全表掃描。就相當(dāng)于是雙for循環(huán)。如果 t1 和 t2 都是 10 萬(wàn)行的表(當(dāng)然了,這也還是屬于小表的范圍),就要掃描 100 億行。
SimpleNestLoopJoin顯然是很低效的,對(duì)內(nèi)表需要進(jìn)行N次全表掃描,實(shí)際復(fù)雜度是N*M,N是外表的記錄數(shù)目,M是記錄數(shù),代表一次掃描內(nèi)表的代價(jià)。為此,MySQL針對(duì)SimpleNestLoopJoin做了若干優(yōu)化。

Index Nested-Loop Join

如果我們能對(duì)內(nèi)表的join條件建立索引,那么對(duì)于外表的每條記錄,無(wú)需再進(jìn)行全表掃描內(nèi)表,只需要一次Btree-Lookup即可,整體時(shí)間復(fù)雜度降低為N*O(logM)。
再來(lái)看看這一句

select * from t1 straight_join t2 on (t1.a=t2.a);

在這條語(yǔ)句里,被驅(qū)動(dòng)表 t2 的字段 a 上有索引,join 過(guò)程用上了這個(gè)索引,因此這個(gè)語(yǔ)句的執(zhí)行流程是這樣的:

執(zhí)行流程示意圖如下:


對(duì)比HashJoin,對(duì)于外表每條記錄,HashJoin是一次HashTable的search,當(dāng)然HashTable也有build時(shí)間,還需要處理內(nèi)存不足的情況,不一定比INLJ好。

Block Nested-Loop Join

MySQL采用了批量技術(shù),即一次利用join_buffer_size緩存足夠多的記錄,每次遍歷內(nèi)表時(shí),每條內(nèi)表記錄與這一批數(shù)據(jù)進(jìn)行條件判斷,這樣就減少了掃描內(nèi)表的次數(shù),如果內(nèi)表比較大,間接就緩解了IO的讀壓力。
Simple Nested-Loop Join 與 Block Nested-Loop Join從時(shí)間復(fù)雜度上來(lái)說(shuō),這兩個(gè)算法是一樣的。但是,Block Nested-Loop Join是內(nèi)存操作,速度上會(huì)快很多,性能也更好。
示意圖如下:

Batched Key Access

IndexNestLoopJoin利用join條件的索引,通過(guò)Btree-Lookup去匹配減少了遍歷內(nèi)表的代價(jià)。如果join條件是非主鍵列,那么意味著大量的回表和隨機(jī)IO。BKA優(yōu)化的做法是,將滿足條件的一批數(shù)據(jù)按主鍵排序,這樣回表時(shí),從主鍵的角度來(lái)說(shuō)就相對(duì)有序,緩解隨機(jī)IO的代價(jià)。BKA實(shí)際上是利用了MRR特性(MultiRangeRead),訪問(wèn)數(shù)據(jù)之前,先將主鍵排序,然后再訪問(wèn)。主鍵排序的緩存大小通過(guò)參數(shù)read_rnd_buffer_size控制。

Hash Join算法

NestLoopJoin算法簡(jiǎn)單來(lái)說(shuō),就是雙重循環(huán),遍歷外表(驅(qū)動(dòng)表),對(duì)于外表的每一行記錄,然后遍歷內(nèi)表,然后判斷join條件是否符合,進(jìn)而確定是否將記錄吐出給上一個(gè)執(zhí)行節(jié)點(diǎn)。從算法角度來(lái)說(shuō),這是一個(gè)M*N的復(fù)雜度。HashJoin是針對(duì)equal-join場(chǎng)景的優(yōu)化,基本思想是,將外表數(shù)據(jù)load到內(nèi)存,并建立hash表,這樣只需要遍歷一遍內(nèi)表,就可以完成join操作,輸出匹配的記錄。如果數(shù)據(jù)能全部load到內(nèi)存當(dāng)然好,邏輯也簡(jiǎn)單,一般稱這種join為CHJ(Classic Hash Join),之前MariaDB就已經(jīng)實(shí)現(xiàn)了這種HashJoin算法。如果數(shù)據(jù)不能全部load到內(nèi)存,就需要分批load進(jìn)內(nèi)存,然后分批join,下面具體介紹這幾種join算法的實(shí)現(xiàn)。

In-Memory Join(CHJ)

HashJoin一般包括兩個(gè)過(guò)程,創(chuàng)建hash表的build過(guò)程和探測(cè)hash表的probe過(guò)程。
1).build phase
遍歷外表,以join條件為key,查詢需要的列作為value創(chuàng)建hash表。這里涉及到一個(gè)選擇外表的依據(jù),主要是評(píng)估參與join的兩個(gè)表(結(jié)果集)的大小來(lái)判斷,誰(shuí)小就選擇誰(shuí),這樣有限的內(nèi)存更容易放下hash表。
2).probe phase
hash表build完成后,然后逐行遍歷內(nèi)表,對(duì)于內(nèi)表的每個(gè)記錄,對(duì)join條件計(jì)算hash值,并在hash表中查找,如果匹配,則輸出,否則跳過(guò)。所有內(nèi)表記錄遍歷完,則整個(gè)過(guò)程就結(jié)束了

On-Disk Hash Join

CHJ的限制條件在于,要求內(nèi)存能裝下整個(gè)外表。在MySQL中,Join可以使用的內(nèi)存通過(guò)參數(shù)join_buffer_size控制。如果join需要的內(nèi)存超出了join_buffer_size,那么CHJ將無(wú)能為力,只能對(duì)外表分成若干段,每個(gè)分段逐一進(jìn)行build過(guò)程,然后遍歷內(nèi)表對(duì)每個(gè)分段再進(jìn)行一次probe過(guò)程。假設(shè)外表分成了N片,那么將掃描內(nèi)表N次。這種方式當(dāng)然是比較弱的。

在MySQL8.0中,如果join需要內(nèi)存超過(guò)了join_buffer_size,build階段會(huì)首先利用hash算將外表進(jìn)行分區(qū),并產(chǎn)生臨時(shí)分片寫到磁盤上;然后在probe階段,對(duì)于內(nèi)表使用同樣的hash算法進(jìn)行分區(qū)。由于使用分片hash函數(shù)相同,那么key相同(join條件相同)必然在同一個(gè)分片編號(hào)中。接下來(lái),再對(duì)外表和內(nèi)表中相同分片編號(hào)的數(shù)據(jù)進(jìn)行CHJ的過(guò)程,所有分片的CHJ做完,整個(gè)join過(guò)程就結(jié)束了。這種算法的代價(jià)是,對(duì)外表和內(nèi)表分別進(jìn)行了兩次讀IO,一次寫IO。相對(duì)于之之前需要N次掃描內(nèi)表IO,現(xiàn)在的處理方式更好。
順序?yàn)?#xff1a;外表的分片、內(nèi)表分片、哈希連接

參考鏈接

join語(yǔ)句怎么優(yōu)化?
MySQL8.0 新特性 Hash Join
哈希加入MySQL 8
MySQL · 新特征 · MySQL 哈希連接實(shí)現(xiàn)介紹

總結(jié)

以上是生活随笔為你收集整理的《DBNotes:Join算法的前世今生》的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。