亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Doris Join 優(yōu)化原理文檔詳解

 更新時間:2022年10月26日 15:23:52   作者:doris文檔  
這篇文章主要為大家介紹了Doris Join 優(yōu)化原理文檔詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

Doris Join 優(yōu)化原理

Doris 支持兩種物理算子,一類是 Hash Join,另一類是 Nest Loop Join。

  • Hash Join:在右表上根據(jù)等值 Join 列建立哈希表,左表流式的利用哈希表進行 Join 計算,它的限制是只能適用于等值 Join。
  • Nest Loop Join:通過兩個 for 循環(huán),很直觀。然后它適用的場景就是不等值的 Join,例如:大于小于或者是需要求笛卡爾積的場景。它是一個通用的 Join 算子,但是性能表現(xiàn)差。

作為分布式的 MPP 數(shù)據(jù)庫, 在 Join 的過程中是需要進行數(shù)據(jù)的 Shuffle。數(shù)據(jù)需要進行拆分調(diào)度,才能保證最終的 Join 結(jié)果是正確的。舉個簡單的例子,假設(shè)關(guān)系S 和 R 進行Join,N 表示參與 Join 計算的節(jié)點的數(shù)量;T 則表示關(guān)系的 Tuple 數(shù)目。

Doris Shuffle 方式

Doris 支持 4 種 Shuffle 方式

Broadcast Join

它要求把右表全量的數(shù)據(jù)都發(fā)送到左表上,即每一個參與 Join 的節(jié)點,它都擁有右表全量的數(shù)據(jù),也就是 T(R)。

它適用的場景是比較通用的,同時能夠支持 Hash Join 和 Nest loop Join,它的網(wǎng)絡(luò)開銷 N * T(R)。

左表數(shù)據(jù)不移動,右表數(shù)據(jù)發(fā)送到左表數(shù)據(jù)的掃描節(jié)點。

Shuffle Join

當進行 Hash Join 時候,可以通過 Join 列計算對應(yīng)的 Hash 值,并進行 Hash 分桶。

它的網(wǎng)絡(luò)開銷則是:T(R) + T(N),但它只能支持 Hash Join,因為它是根據(jù) Join 的條件也去做計算分桶的。

左右表數(shù)據(jù)根據(jù)分區(qū),計算的記過發(fā)送到不同的分區(qū)節(jié)點上。

Bucket Shuffle Join

Doris 的表數(shù)據(jù)本身是通過 Hash 計算分桶的,所以就可以利用表本身的分桶列的性質(zhì)來進行 Join 數(shù)據(jù)的 Shuffle。假如兩張表需要做 Join,并且 Join 列是左表的分桶列,那么左表的數(shù)據(jù)其實可以不用去移動右表通過左表的數(shù)據(jù)分桶發(fā)送數(shù)據(jù)就可以完成 Join 的計算。

它的網(wǎng)絡(luò)開銷則是:T(R)相當于只 Shuffle 右表的數(shù)據(jù)就可以了。

左表數(shù)據(jù)不移動,右表數(shù)據(jù)根據(jù)分區(qū)計算的結(jié)果發(fā)送到左表掃表的節(jié)點

Colocate

它與 Bucket Shuffle Join 相似,相當于在數(shù)據(jù)導(dǎo)入的時候,根據(jù)預(yù)設(shè)的 Join 列的場景已經(jīng)做好了數(shù)據(jù)的 Shuffle。那么實際查詢的時候就可以直接進行 Join 計算而不需要考慮數(shù)據(jù)的 Shuffle 問題了。

數(shù)據(jù)已經(jīng)預(yù)先分區(qū),直接在本地進行 Join 計算

四種 Shuffle 方式對比

Shuffle方式網(wǎng)絡(luò)開銷物理算子適用場景
BroadCastN * T(R)Hash Join / Nest Loop Join通用
ShuffleT(S) + T(R)Hash Join通用
Bucket ShuffleT(R)Hash JoinJoin條件中存在左表的分布式列,且左表執(zhí)行時為單分區(qū)
Colocate0Hash JoinJoin條件中存在左表的分布式列,切左右表同屬于一個Colocate Group

N : 參與 Join 計算的 Instance 個數(shù)

T(關(guān)系) : 關(guān)系的 Tuple 數(shù)目

上面這 4 種方式靈活度是從高到低的,它對這個數(shù)據(jù)分布的要求是越來越嚴格,但 Join 計算的性能也是越來越好的。

Runtime Filter Join 優(yōu)化

Doris 在進行 Hash Join 計算時會在右表構(gòu)建一個哈希表,左表流式的通過右表的哈希表從而得出 Join 結(jié)果。而 RuntimeFilter 就是充分利用了右表的 Hash 表,在右表生成哈希表的時,同時生成一個基于哈希表數(shù)據(jù)的一個過濾條件,然后下推到左表的數(shù)據(jù)掃描節(jié)點。通過這樣的方式,Doris 可以在運行時進行數(shù)據(jù)過濾。

假如左表是一張大表,右表是一張小表,那么利用右表生成的過濾條件就可以把絕大多數(shù)在 Join 層要過濾的數(shù)據(jù)在數(shù)據(jù)讀取時就提前過濾,這樣就能大幅度的提升 Join 查詢的性能。

當前 Doris 支持三種類型 RuntimeFilter

  • 一種是 IN,很好理解,將一個 hashset 下推到數(shù)據(jù)掃描節(jié)點。
  • 第二種就是 BloomFilter,就是利用哈希表的數(shù)據(jù)構(gòu)造一個 BloomFilter,然后把這個 BloomFilter 下推到查詢數(shù)據(jù)的掃描節(jié)點。。
  • 最后一種就是 MinMax,就是個 Range 范圍,通過右表數(shù)據(jù)確定 Range 范圍之后,下推給數(shù)據(jù)掃描節(jié)點。

Runtime Filter 適用的場景有兩個要求:

  • 第一個要求就是左表大右表小,因為構(gòu)建 Runtime Filter是需要承擔計算成本的,包括一些內(nèi)存的開銷。
  • 第二個要求就是左右表 Join 出來的結(jié)果很少,說明這個 Join 可以過濾掉左表的絕大部分數(shù)據(jù)。

當符合上面兩個條件的情況下,開啟 Runtime Filter 就能收獲比較好的效果

當 Join 列為左表的 Key 列時,RuntimeFilter 會下推到存儲引擎。Doris 本身支持延遲物化,

延遲物化簡單來說是這樣的:假如需要掃描 A、B、C 三列,在 A 列上有一個過濾條件: A 等于 2,要掃描 100 行的話,可以先把 A 列的 100 行掃描出來,再通過 A = 2 這個過濾條件過濾。之后通過過濾完成后的結(jié)果,再去讀取 B、C 列,這樣就能極大的降低數(shù)據(jù)的讀取 IO。所以說 Runtime Filter 如果在 Key 列上生成,同時利用 Doris 本身的延遲物化來進一步提升查詢的性能。

Runtime Filter 類型

Doris 提供了三種不同的 Runtime Filter 類型:

  • IN 的優(yōu)點就是效果過濾效果明顯,且快速。它的缺點首先第一個它只適用于 BroadCast,第二,它右表超過一定數(shù)據(jù)量的時候就失效了,當前 Doris 目前配置的是1024,即右表如果大于 1024,IN 的 Runtime Filter 就直接失效了。
  • MinMax 的優(yōu)點是開銷比較小。它的缺點就是對數(shù)值列還有比較好的效果,但對于非數(shù)值列,基本上就沒什么效果。
  • Bloom Filter 的特點就是通用,適用于各種類型、效果也比較好。缺點就是它的配置比較復(fù)雜并且計算較高。

Join Reorder

數(shù)據(jù)庫一旦涉及到多表 Join,Join 的順序?qū)φ麄€ Join 查詢的性能是影響很大的。假設(shè)有三張表 Join,參考下面這張圖,左邊是 a 表跟 b 張表先做 Join,中間結(jié)果的有 2000 行,然后與 c 表再進行 Join 計算。

接下來看右圖,把 Join 的順序調(diào)整了一下。把 a 表先與 c 表 Join,生成的中間結(jié)果只有 100,然后最終再與 b 表 Join 計算。最終的 Join 結(jié)果是一樣的,但是它生成的中間結(jié)果有 20 倍的差距,這就會產(chǎn)生一個很大的性能 Diff 了。

Doris 目前支持基于規(guī)則的 Join Reorder 算法。它的邏輯是:

  • 讓大表、跟小表盡量做 Join,它生成的中間結(jié)果是盡可能小的。
  • 把有條件的 Join 表往前放,也就是說盡量讓有條件的 Join 表進行過濾
  • Hash Join 的優(yōu)先級高于 Nest Loop Join,因為 Hash join 本身是比 Nest Loop Join 快很多的。

Doris Join 調(diào)優(yōu)方法

Doris Join 調(diào)優(yōu)的方法:

  • 利用 Doris 本身提供的 Profile,去定位查詢的瓶頸。Profile 會記錄 Doris 整個查詢當中各種信息,這是進行性能調(diào)優(yōu)的一手資料。。
  • 了解 Doris 的 Join 機制,這也是第二部分跟大家分享的內(nèi)容。知其然知其所以然、了解它的機制,才能分析它為什么比較慢。
  • 利用 Session 變量去改變 Join 的一些行為,從而實現(xiàn) Join 的調(diào)優(yōu)。
  • 查看 Query Plan 去分析這個調(diào)優(yōu)是否生效。

上面的 4 步基本上完成了一個標準的 Join 調(diào)優(yōu)流程,接著就是實際去查詢驗證它,看看效果到底怎么樣。

如果前面 4 種方式串聯(lián)起來之后,還是不奏效。這時候可能就需要去做 Join 語句的改寫,或者是數(shù)據(jù)分布的調(diào)整、需要重新去 Recheck 整個數(shù)據(jù)分布是否合理,包括查詢 Join 語句,可能需要做一些手動的調(diào)整。當然這種方式是心智成本是比較高的,也就是說要在嘗試前面方式不奏效的情況下,才需要去做進一步的分析。

調(diào)優(yōu)案例實戰(zhàn)

案例一

一個四張表 Join 的查詢,通過 Profile 的時候發(fā)現(xiàn)第二個 Join 耗時很高,耗時 14 秒。

進一步分析 Profile 之后,發(fā)現(xiàn) BuildRows,就是右表的數(shù)據(jù)量是大概 2500 萬。而 ProbeRows ( ProbeRows 是左表的數(shù)據(jù)量)只有 1 萬多。這種場景下右表是遠遠大于左表,這顯然是個不合理的情況。這顯然說明 Join 的順序出現(xiàn)了一些問題。這時候嘗試改變 Session 變量,開啟 Join Reorder。

set enable_cost_based_join_reorder = true

這次耗時從 14 秒降到了 4 秒,性能提升了 3 倍多。

此時再 Check Profile 的時候,左右表的順序已經(jīng)調(diào)整正確,即右表是大表,左表是小表?;谛”砣?gòu)建哈希表,開銷是很小的,這就是典型的一個利用 Join Reorder 去提升 Join 性能的一個場景

案例二

存在一個慢查詢,查看 Profile 之后,整個 Join 節(jié)點耗時大概44秒。它的右表有 1000 萬,左表有 6000 萬,最終返回的結(jié)果也只有 6000 萬。

這里可以大致的估算出過濾率是很高的,那為什么 Runtime Filter 沒有生效呢?通過 Query Plan 去查看它,發(fā)現(xiàn)它只開啟了 IN 的 Runtime Filter。

當右表超過1024行的話, IN 是不生效的,所以根本起不到什么過濾的效果,所以嘗試調(diào)整 RuntimeFilter 的類型。

這里改為了 BloomFilter,左表的 6000 萬條數(shù)據(jù)過濾了 5900 萬條?;旧?99% 的數(shù)據(jù)都被過濾掉了,這個效果是很顯著的。查詢也從原來的 44 秒降到了 13 秒,性能提升了大概也是三倍多。

案例三

下面是一個比較極端的 Case,通過一些環(huán)境變量調(diào)優(yōu)也沒有辦法解決,因為它涉及到 SQL Rewrite,所以這里列出來了原始的 SQL 。

select 100.00 * sum (case
        when P_type like 'PROMOS'
        then 1 extendedprice * (1 - 1 discount)
        else 0
        end ) / sum(1 extendedprice * (1 - 1 discount)) as promo revenue
from lineitem, part
where
    1_partkey = p_partkey
    and 1_shipdate >= date '1997-06-01'
    and 1 shipdate < date '1997-06-01' + interval '1' month

這個 Join 查詢是很簡單的,單純的一個左右表的 Join 。當然它上面有一些過濾條件,打開 Profile 的時候,發(fā)現(xiàn)整個查詢 Hash Join 執(zhí)行了三分多鐘,它是一個 BroadCast 的 Join,它的右表有 2 億條,左表只有 70 萬。在這種情況下選擇了 Broadcast Join 是不合理的,這相當于要把 2 億條做一個 Hash Table,然后用 70 萬條遍歷兩億條的 Hash Table ,這顯然是不合理的。

為什么會產(chǎn)生不合理的 Join 順序呢?其實這個左表是一個 10 億條級別的大表,它上面加了兩個過濾條件,加完這兩個過濾條件之后, 10 億條的數(shù)據(jù)就剩 70 萬條了。但 Doris 目前沒有一個好的統(tǒng)計信息收集的框架,所以它不知道這個過濾條件的過濾率到底怎么樣。所以這個 Join 順序安排的時候,就選擇了錯誤的 Join 的左右表順序,導(dǎo)致它的性能是極其低下的。

下圖是改寫完成之后的一個 SQL 語句,在 Join 后面添加了一個Join Hint,在Join 后面加一個方括號,然后把需要的 Join 方式寫入。這里選擇了 Shuffle Join,可以看到右邊它實際查詢計劃里面看到這個數(shù)據(jù)確實是做了 Partition ,原先 3 分鐘的耗時通過這樣的改寫完之后只剩下 7 秒,性能提升明顯

Doris Join 調(diào)優(yōu)建議

最后我們總結(jié) Doris Join 優(yōu)化調(diào)優(yōu)的四點建議:

  • 第一點:在做 Join 的時候,要盡量選擇同類型或者簡單類型的列,同類型的話就減少它的數(shù)據(jù) Cast,簡單類型本身 Join 計算就很快。
  • 第二點:盡量選擇 Key 列進行 Join, 原因前面在 Runtime Filter 的時候也介紹了,Key 列在延遲物化上能起到一個比較好的效果。
  • 第三點:大表之間的 Join ,盡量讓它 Co-location ,因為大表之間的網(wǎng)絡(luò)開銷是很大的,如果需要去做 Shuffle 的話,代價是很高的。
  • 第四點:合理的使用 Runtime Filter,它在 Join 過濾率高的場景下效果是非常顯著的。但是它并不是萬靈藥,而是有一定副作用的,所以需要根據(jù)具體的 SQL 的粒度做開關(guān)。
  • 最后:要涉及到多表 Join 的時候,需要去判斷 Join 的合理性。盡量保證左表為大表,右表為小表,然后 Hash Join 會優(yōu)于 Nest Loop Join。必要的時可以通過 SQL Rewrite,利用 Hint 去調(diào)整 Join 的順序。

以上就是Doris Join 優(yōu)化原理文檔詳解的詳細內(nèi)容,更多關(guān)于Doris Join 優(yōu)化原理的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論