Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解
Mysql hash join之classic hash join CHJ過程詳解
hash join的歷史
優(yōu)化器里的hash join算法在SQL Server、Oracle、postgress等數(shù)據(jù)庫早已實(shí)現(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 nestloop join and batched key access等算法,這也是hash join算法被推遲實(shí)現(xiàn)的部分原因。
hash join的概述
提到hash join之前自然得說Nestloopjoin,以兩個(gè)表的關(guān)聯(lián)為例,它其實(shí)是個(gè)雙層循環(huán),先遍歷外層的表(n條),再拿每次對應(yīng)的值去匹配、循環(huán)遍歷內(nèi)部的表(M條)。這樣顯然會(huì)有M*n的計(jì)算復(fù)雜度。如果能將外部表先裝載到內(nèi)存,然后再做內(nèi)部表的匹配、遍歷,計(jì)算的復(fù)雜度就會(huì)大大降低,這就是hash join的思想。
hash join的類型
hash join 從具體實(shí)現(xiàn)上又分為:
1經(jīng)典hash join(In-Memory?Join或classic hash join或CHJ)
2 磁盤分區(qū)hash join (On-Disk Hash Join)
3 Grace Hash Join
4 混合hash join(hybrid hash join)
hash join應(yīng)用場景
hash join主要應(yīng)用在以下條件:
1兩個(gè)或多個(gè)表至少包含一個(gè)等值條件關(guān)聯(lián)時(shí)。
2 關(guān)聯(lián)的字段上沒有索引。
3 關(guān)聯(lián)條件可以是原始字段或者表達(dá)式(如 T1.col1+T1.col2 = T2.col3+T2.col4).
4 關(guān)聯(lián)條件等號的兩表只能出現(xiàn)一張表。
5 補(bǔ)充,可能使用到hash join的SQL寫法示例:
CREATE TABLE t1 (t1_1 INT, t1_2 INT);CREATE TABLE t2 (t2_1 INT, t2_2 INT)SELECT * FROM t1 JOIN t2 ON (t1.t1_1 = t2.t2_1);SELECT * FROM t1 JOIN t2 ON (t1.t1_1 = t2.t2_1 AND t1.t1_2 = t2.t2_2);SELECT * FROM t1 JOIN t2 ON (t1.t1_1 = t2.t2_1 AND t2.t2_2 > 43);SELECT * FROM t1 JOIN t2 ON (t1.t1_1 + t1.t1_2 = t2.t2_1);SELECT * FROM t1 JOIN t2 ON (FLOOR(t1.t1_1 + t1.t1_2) = CEIL(t2.t2_1 = t2.t2_2));In-Memory?Join classic hash join
經(jīng)典hash join(classic hash join)簡稱CHJ,該算法由兩部分構(gòu)成,一是構(gòu)建哈希表(hash table)過程,二是探測、匹配(probe)過程。
以有如下查詢和表格結(jié)構(gòu)為例:
CREATE TABLE t1 (foo INT);
CREATE TABLE t2 (bar INT);
insert into t1 values(12);
insert into t2 values(34);
… ...? -- 插入數(shù)據(jù)省略
SELECT * FROM t1 JOIN t2 on (t1.foo = t2.bar);
構(gòu)建哈希表:
1 當(dāng)兩個(gè)表以含等值條件方式關(guān)聯(lián)時(shí)其中一個(gè)表會(huì)被指定為構(gòu)建表,該表會(huì)以哈希表(哈希的值來自于等值條件里的字段)的形式讀入內(nèi)存。
2 假設(shè)這里t1表被指定為構(gòu)建表,那么將會(huì)通過哈希函數(shù)產(chǎn)生哈希表,這里t1的foo字段是是哈希函數(shù)里的鍵。
探測階段:
此時(shí)join里的另外個(gè)表即t2作為探測表,在構(gòu)建完成后,開始從t2探測表作為輸入。這時(shí)以t2的bar (t1、t2兩表關(guān)聯(lián)時(shí)t2的字段)作為哈希的鍵,同時(shí)該鍵是用來匹配內(nèi)存里的t1生成的哈希表。一旦匹配到記錄則意味著找到目標(biāo),這個(gè)按照每一行匹配的過程就做探測過程。
In-Memory?Join過程示意
構(gòu)建階段示例 探測階段示例????執(zhí)行計(jì)劃查看In-Memory Join
EXPLAIN ANALYZE SELECT CountryCode, country.Name AS Country, city.Name AS City, city.District FROM world.country IGNORE INDEX (Primary) INNER JOIN world.city IGNORE INDEX (CountryCode) ON city.CountryCode = country.Code WHERE Continent = 'Asia';-- 數(shù)據(jù)庫來自mysql官網(wǎng)示例數(shù)據(jù)庫world -- 結(jié)果 EXPLAIN -> Inner hash join (world.city.CountryCode = world.country.`Code`) (cost=13870.82 rows=595) (actual time=58.807..134.662 rows=1766 loops=1)-> Table scan on city (cost=0.80 rows=4046) (actual time=30.193..95.386 rows=4079 loops=1)-> Hash-> Filter: (world.country.Continent = 'Asia') (cost=30.90 rows=34) (actual time=21.446..28.489 rows=51 loops=1)-> Table scan on country (cost=30.90 rows=239) (actual time=21.435..28.338 rows=239 loops=1)執(zhí)行示例
?過程介紹
Step1:Country的Code字段會(huì)被哈希函數(shù)哈希并保存在關(guān)聯(lián)緩存(即哈希表)內(nèi)(join buffer)。
Step2:然后通過和step1里一樣的哈希函數(shù)哈希的字段CountryCode進(jìn)行表掃描(table scan)遍歷city表里的每一行。
總結(jié)
以上是生活随笔為你收集整理的Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL 聚合函数一定要跟group by
- 下一篇: linux cmake编译源码,linu