Mysql 优化器内部JOIN算法hash join On-Disk Hash Join Grace Hash Join Hybrid hash join过程详解
Mysql 各種hash join算法講解
hash join的概述
提到hash join之前自然得說Nest loop join,以兩個表的關(guān)聯(lián)為例,它其實是個雙層循環(huán),先遍歷外層的表(n條),再拿每次對應(yīng)的值去匹配、循環(huán)遍歷內(nèi)部的表(M條)。這樣顯然會有M*n的計算復(fù)雜度。如果能將外部表先裝載到內(nèi)存,然后再做內(nèi)部表的匹配、遍歷,計算的復(fù)雜度就會大大降低,這就是hash join的思想。
本文繼續(xù)介紹hash join的其它幾個算法On-Disk Hash Join、Grace Hash Join、Hybrid hash join。其中In Memory?Join classic hash join的介紹見:
Mysql 優(yōu)化器內(nèi)部JOIN算法hash join Nestloopjoin及classic hash join CHJ過程詳解_數(shù)據(jù)科學(xué)匯集-CSDN博客Mysql hash join之classic hash join CHJ過程詳解hash join的歷史優(yōu)化器里的hash join算法在SQL Server、Oracle、postgress等數(shù)據(jù)庫早已實現(xiàn),而Mysql在8.0.18之后才支持。在8.0.18之前mysql只支持嵌套循環(huán)關(guān)聯(lián)(nested loop join),這其中最簡單就是簡易嵌套循環(huán)關(guān)聯(lián)simple nestloop join,隨后mysql做了改進(jìn)進(jìn)而支持block nestloop join, index nestlohttps://shenliang.blog.csdn.net/article/details/120498088
On-Disk Hash Join
CHJ算法在構(gòu)建表時的內(nèi)存大小可通過參數(shù)join_buffer_size來設(shè)置,但因為需要把整個表都裝到內(nèi)存里,所以這種方法遇到比較大的表時就顯得捉襟見肘。不過也不是沒有方法去規(guī)避,我們按照如下的策略方向做改進(jìn)(分批執(zhí)行的思想,記作):
1 在構(gòu)建哈希表時讀取盡量多的內(nèi)容到內(nèi)存。
2 運行探測過程時讀取整個探測的輸入(即對應(yīng)1里的內(nèi)容)。
3 擦除(清空)內(nèi)存里的哈希表。
4 循環(huán)步驟1里執(zhí)行直至遍歷完構(gòu)建過程里的數(shù)據(jù)。
不過因為需要多次讀取構(gòu)建的輸入(即構(gòu)建表)還是有風(fēng)險且有成本的,假設(shè)構(gòu)建表被分成了n份,那么在匹配探測表時將會掃描n次。這時借助磁盤分區(qū)執(zhí)行的方法on-Disk Hash Join就應(yīng)運而生了。詳細(xì)步驟見下:
Step1:把構(gòu)建表和探測表在磁盤上分成若干小區(qū)(塊),這里分配的原則是每個小區(qū)(塊)能全部裝載到內(nèi)存里,而構(gòu)建表的確定和classic hash join算法類似(一般優(yōu)先選擇小表)。
Step2:當(dāng)所有的記錄都已經(jīng)分區(qū)(塊)到磁盤上的小文件后,開始遍歷分區(qū)(塊),進(jìn)入構(gòu)建階段即將第一個分區(qū)通過函數(shù)函數(shù)裝載到內(nèi)存里形成哈希表,然后在探測階段掃描第一個分區(qū)(塊),該分區(qū)(塊)對應(yīng)構(gòu)建階段里分區(qū)。因為在生成分區(qū)信息時構(gòu)建表和探測表用相同的哈希函數(shù),所以在探測階段進(jìn)行匹配時很容易找到對應(yīng)的分區(qū)信息。
Step3:當(dāng)?shù)谝粋€分區(qū)(塊)處理完了之后清空內(nèi)存里的哈希表,然后把第二個分區(qū)文件裝載到構(gòu)建表,在探測過程用第二個分區(qū)的信息匹配探測表,依次類推直至所有的分區(qū)(塊)都遍歷完。
通過對On-Disk Hash Join的執(zhí)行過程進(jìn)行分析,我們不難發(fā)現(xiàn)該算法會在構(gòu)建過程讀取IO兩次、探測過程寫一次IO。這與開頭里介紹的hash join改善算法(n次IO掃描探測表)已經(jīng)有較大的進(jìn)步。
構(gòu)建表分區(qū) 探測表分區(qū) 構(gòu)建探測兩過程??????注:
1 in-memory hash join和on-disk hash join算法都是用的msxxHash64作為哈希函數(shù),它是在提供高質(zhì)量的哈希值的同時又能保證快速(減少哈希沖突的數(shù)量)。
2 如果有一個數(shù)據(jù)集傾斜的結(jié)果集會導(dǎo)致構(gòu)建表里的一個分區(qū)(塊)不能填入內(nèi)存,那么hash join算法會按照如下的邏輯處理:
1 讀取盡量多的分區(qū)(塊)到內(nèi)存。
2 在整個探測階段讀取探測分區(qū)。
3 清空內(nèi)存里的哈希表。
4 調(diào)轉(zhuǎn)到步驟1直至構(gòu)建分區(qū)里沒有數(shù)據(jù)。
Grace Hash Join
當(dāng)連接緩存大小(join buffer size)不足時,mysql會先分片再按照classic hash join的方式處理(見On-Disk Hash Join里的注2)。但在極端情況,如果數(shù)據(jù)分布不均勻,有大量數(shù)據(jù)經(jīng)過哈希后分布到一個桶內(nèi),這將導(dǎo)致分片后的連接緩存大小仍然不足。碰到這種情況oracle的grace hash join算法則會繼續(xù)拆分直至有足夠的內(nèi)存可以存放哈希表,當(dāng)然如果在關(guān)聯(lián)條件相同的情況下不論再怎么哈希還是不能拆分時grace hash join也退化為和像mysql一樣先分片再classic hash join的方式處理方式。
Hybrid hash join
如果緩存足夠多的分片數(shù)據(jù)會盡量緩存,那么就不必像GraceHash那樣將所有分片都先讀進(jìn)內(nèi)存,再寫到外存,最后再讀進(jìn)內(nèi)存進(jìn)行build過程,這就是Grace Hash Join算法的核心,即在內(nèi)存相對于分片比較充裕的情況下可以減少磁盤的讀寫IO。目前Oceanbase的HashJoin采用的是這種join方式。
hash join的偽代碼
result = [] join_buffer = [] partitions = 0 on_disk = False for country_row in country:if country_row.Continent == 'Asia':hash = xxHash64(country_row.Code)if not on_disk:join_buffer.append(hash)if is_full(join_buffer):# Create partitions on diskon_disk = Truepartitions = write_buffer_to_disk(join_buffer)join_buffer = []elsewrite_hash_to_disk(hash)if not on_disk:for city_row in city:hash = xxHash64(city_row.CountryCode)if hash in join_buffer:country_row = get_row(hash)city_row = get_row(hash)result.append(join_rows(country_row, city_row))else:for city_row in city:hash = xxHash64(city_row.CountryCode)write_hash_to_disk(hash) for partition in range(partitions):join_buffer = load_build_from_disk(partition)for hash in load_hash_from_disk(partition):if hash in join_buffer:country_row = get_row(hash)city_row = get_row(hash)result.append(join_rows(country_row, city_row)) join_buffer = []代碼簡介
從country表里讀取每一行并計算code字段對應(yīng)的哈希值并存儲在連接緩存內(nèi)(join buffer)。如果連接緩存滿了則走on-disk算法并哈希后的緩存寫到外部磁盤。也正是在此時分區(qū)的個數(shù)確定,然后對country表剩下的數(shù)據(jù)繼續(xù)哈希。
?對于in-memory的算法只需要通過循環(huán)比較city和緩存里的哈希值即可,而對于on-disk算法哈希的city表會被首先計算并存放在磁盤然后再通過分區(qū)一個個的匹配。
參考:
MySQL :: WL#2241: Hash join
New features of MySQL 8.0 hash join | Develop Paper
總結(jié)
以上是生活随笔為你收集整理的Mysql 优化器内部JOIN算法hash join On-Disk Hash Join Grace Hash Join Hybrid hash join过程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 技嘉电脑怎么用u盘启动不了 技嘉电脑无法
- 下一篇: win7默认浏览器怎么设置 如何将默认浏