SQL中基于代价的优化
還記得筆者在上篇文章無意中挖的一個(gè)坑么?如若不知,強(qiáng)烈建議看官先行閱讀前面兩文-《SparkSQL Join原理》和《Join中竟然也有謂詞下推?》
第一篇文章主要分析了大數(shù)據(jù)領(lǐng)域Join的三種基礎(chǔ)算法以及各自的適用場景,第二篇文章在第一篇的基礎(chǔ)上進(jìn)一步深入,討論了Join基礎(chǔ)算法的一種優(yōu)化方案 – Runtime Filter,文章最后還引申地聊了聊謂詞下推技術(shù)。同時(shí),在第二篇文章開頭,筆者引出了兩個(gè)問題,SQL執(zhí)行引擎如何知曉參與Join的兩波數(shù)據(jù)集大小?衡量兩波數(shù)據(jù)集大小的是物理大小還是紀(jì)錄多少抑或兩者都有?這關(guān)系到SQL解析器如何正確選擇Join算法的問題。好了,這些就是這篇文章要為大家?guī)淼淖h題-基于代價(jià)優(yōu)化(Cost-Based Optimization,簡稱CBO)。
CBO基本原理
提到CBO,就不得不提起一位’老熟人’ – 基于規(guī)則優(yōu)化(Rule-Based Optimization,簡稱RBO)。RBO是一種經(jīng)驗(yàn)式、啟發(fā)式的優(yōu)化思路,優(yōu)化規(guī)則都已經(jīng)預(yù)先定義好,只需要將SQL往這些規(guī)則上套就可以(對(duì)RBO還不了解的童鞋,可以參考筆者的另一篇文章 – 《從0到1認(rèn)識(shí)Catalyst》)。說白了,RBO就像是一個(gè)經(jīng)驗(yàn)豐富的老司機(jī),基本套路全都知道。
然而世界上有一種東西叫做 – 不按套路來,與其說它不按套路來,倒不如說它本身并沒有什么套路。最典型的莫過于復(fù)雜Join算子優(yōu)化,對(duì)于這些Join來說,通常有兩個(gè)選擇題要做:
1、Join應(yīng)該選擇哪種算法策略來執(zhí)行?BroadcastJoin or ShuffleHashJoin or SortMergeJoin?不同的執(zhí)行策略對(duì)系統(tǒng)的資源要求不同,執(zhí)行效率也有天壤之別,同一個(gè)SQL,選擇到合適的策略執(zhí)行可能只需要幾秒鐘,而如果沒有選擇到合適的執(zhí)行策略就可能會(huì)導(dǎo)致系統(tǒng)OOM。
2、對(duì)于雪花模型或者星型模型來講,多表Join應(yīng)該選擇什么樣的順序執(zhí)行?不同的Join順序意味著不同的執(zhí)行效率,比如A join B join C,A、B表都很大,C表很小,那A join B很顯然需要大量的系統(tǒng)資源來運(yùn)算,執(zhí)行時(shí)間必然不會(huì)短。而如果使用A join C join B的執(zhí)行順序,因?yàn)镃表很小,所以A join C會(huì)很快得到結(jié)果,而且結(jié)果集會(huì)很小,再使用小的結(jié)果集 join B,性能顯而易見會(huì)好于前一種方案。
大家想想,這有什么固定的優(yōu)化規(guī)則么?并沒有。說白了,你需要知道更多關(guān)于表的基礎(chǔ)信息(表大小、表記錄總條數(shù)等),再通過一定規(guī)則代價(jià)評(píng)估才能從中選擇一條最優(yōu)的執(zhí)行計(jì)劃。CBO意為基于代價(jià)優(yōu)化策略,就是從多個(gè)可能的語法樹中選擇一條代價(jià)最小的語法樹來執(zhí)行,換個(gè)說法,CBO的核心在于評(píng)估出一條給定語法樹的實(shí)際代價(jià)。比如下面這顆SQL語法樹:
要評(píng)估給定整棵樹的代價(jià),分而治之只需要評(píng)估每個(gè)節(jié)點(diǎn)執(zhí)行的代價(jià),最后將所有節(jié)點(diǎn)代價(jià)累加即可。而要評(píng)估單個(gè)節(jié)點(diǎn)執(zhí)行實(shí)際代價(jià),又需要知道兩點(diǎn),其一是這種算子的代價(jià)規(guī)則,每種算子的代價(jià)計(jì)算規(guī)則必然都不同,比如Merge-Sort Join、Shuffle Hash Join、GroupBy都有自己的一套代價(jià)計(jì)算算法。其二是參與操作的數(shù)據(jù)集基本信息(大小、總記錄條數(shù)),比如實(shí)際參與Merge-Sort Join的兩表大小,作為節(jié)點(diǎn)實(shí)際執(zhí)行代價(jià)的一個(gè)重要因素,當(dāng)然非常重要。試想,同樣是Table Scan操作,大表和小表的執(zhí)行代價(jià)必然不同。
為給定算子的代價(jià)進(jìn)行評(píng)估說到底也是一種算法,算法都是死的,暫且不表,下文詳述。而參與的數(shù)據(jù)集基本信息卻是活的,為什么如此說,因?yàn)檫@些數(shù)據(jù)集都是原始表經(jīng)過過濾、聚合之后的中間結(jié)果,沒有規(guī)則直接告訴你這個(gè)中間結(jié)果有多少數(shù)據(jù)!那中間結(jié)果的基本信息如何評(píng)估呢?推導(dǎo)!對(duì),原始表基本信息我們是可以知道的,如果能夠一層一層向上推導(dǎo),是不是就有可能知道所求中間結(jié)果信息!
這里又將任意節(jié)點(diǎn)中間結(jié)果信息評(píng)估拆分為兩個(gè)子問題:首先評(píng)估葉子節(jié)點(diǎn)(原始表)的基本信息,其次一層一層往上推導(dǎo)。評(píng)估原始表基本信息想想總是有辦法的,粗暴點(diǎn)就全表掃描,獲取記錄條數(shù)、最大值、最小值,總之是可以做到的。那基本信息如何一層一層往上推導(dǎo)呢?規(guī)則!比如原始表經(jīng)過 id = 12這個(gè)Filter過濾之后的數(shù)據(jù)集信息(數(shù)據(jù)集大小等)就可以經(jīng)過一定的規(guī)則推導(dǎo)出來,不同算子有不同的規(guī)則,下文詳述!
好吧,上文花費(fèi)了大量時(shí)間將一個(gè)完整的CBO解剖的零零碎碎,變成了一堆規(guī)則加原始表的掃描。相信大家都有點(diǎn)懵懵的。莫慌,我們?cè)賮砝硪槐?#xff1a;
1. 基于代價(jià)優(yōu)化(CBO)原理是計(jì)算所有執(zhí)行路徑的代價(jià),并挑選代價(jià)最小的執(zhí)行路徑。問題轉(zhuǎn)化為:如何計(jì)算一條給定執(zhí)行路徑的代價(jià)
2. 計(jì)算給定路徑的執(zhí)行代價(jià),只需要計(jì)算這條路徑上每個(gè)節(jié)點(diǎn)的執(zhí)行代價(jià),最后相加即可。問題轉(zhuǎn)化為:如何計(jì)算其中任意一個(gè)節(jié)點(diǎn)的執(zhí)行代價(jià)
3. 計(jì)算任意節(jié)點(diǎn)的執(zhí)行代價(jià),只需要知道當(dāng)前節(jié)點(diǎn)算子的代價(jià)計(jì)算規(guī)則以及參與計(jì)算的數(shù)據(jù)集(中間結(jié)果)基本信息(數(shù)據(jù)量大小、數(shù)據(jù)條數(shù)等)。問題轉(zhuǎn)化為:如何計(jì)算中間結(jié)果的基本信息以及定義算子代價(jià)計(jì)算規(guī)則
4. 算子代價(jià)計(jì)算規(guī)則是一種死的規(guī)則,可定義。而任意中間結(jié)果基本信息需要通過原始表基本信息順著語法樹一層一層往上推導(dǎo)得出。問題轉(zhuǎn)化為:如何計(jì)算原始表基本信息以及定義推導(dǎo)規(guī)則
很顯然,上述過程是思維過程,真正工程實(shí)踐是反著由下往上一步一步執(zhí)行,最終得到代價(jià)最小的執(zhí)行路徑。現(xiàn)在再把它從一個(gè)個(gè)零件組裝起來:
1. 首先采集原始表基本信息
2. 再定義每種算子的基數(shù)評(píng)估規(guī)則,即一個(gè)數(shù)據(jù)集經(jīng)過此算子執(zhí)行之后基本信息變化規(guī)則。這兩步完成之后就可以推導(dǎo)出整個(gè)執(zhí)行計(jì)劃樹上所有中間結(jié)果集的數(shù)據(jù)基本信息
3. 定義每種算子的執(zhí)行代價(jià),結(jié)合中間結(jié)果集的基本信息,此時(shí)可以得出任意節(jié)點(diǎn)的執(zhí)行代價(jià)
4. 將給定執(zhí)行路徑上所有算子的代價(jià)累加得到整棵語法樹的代價(jià)
5. 計(jì)算出所有可能語法樹代價(jià),并選出一條代價(jià)最小的
CBO基本實(shí)現(xiàn)思路
上文從理論層面分析了CBO的實(shí)現(xiàn)思路,將完整的CBO功能拆分為了多個(gè)子功能,接下來聊聊對(duì)每一個(gè)子功能的實(shí)現(xiàn)。
第一步:采集參原始表基本信息
這個(gè)操作是CBO最基礎(chǔ)的一項(xiàng)工作,采集的主要信息包括表級(jí)別指標(biāo)和列級(jí)別指標(biāo),如下所示,estimatedSize和rowCount為表級(jí)別信息,basicStats和Histograms為列級(jí)別信息,后者粒度更細(xì),對(duì)優(yōu)化更加重要。
- estimatedSize: 每個(gè)LogicalPlan節(jié)點(diǎn)輸出數(shù)據(jù)大小(解壓)
- rowCount: 每個(gè)LogicalPlan節(jié)點(diǎn)輸出數(shù)據(jù)總條數(shù)
- basicStats: 基本列信息,包括列類型、Max、Min、number of nulls, number of distinct values, max column length, average column length等
- Histograms: Histograms of columns, i.e., equi-width histogram (for numeric and string types) and equi-height histogram (only for numeric types).
這里有兩個(gè)問題值得思考:
1、為什么要采集這些信息?每個(gè)對(duì)象在優(yōu)化過程中起到什么作用?
2、實(shí)際工程一般是如何實(shí)現(xiàn)這些數(shù)據(jù)采集的?
為什么要采集這些信息?很顯然,estimatedSize和rowCount這兩個(gè)值是算子代價(jià)評(píng)估的直觀體現(xiàn),這兩個(gè)值越大,給定算子執(zhí)行代價(jià)必然越大,所以這兩個(gè)值后續(xù)會(huì)用來評(píng)估實(shí)際算子的執(zhí)行代價(jià)。那basicStats和Histograms這倆用來干啥呢,要不忘初心,之所以采集原始表的這些信息,是為了順著執(zhí)行語法樹往上一層一層推導(dǎo)出所有中間結(jié)果的基本信息,這倆就是來干這個(gè)的,至于怎么實(shí)現(xiàn)的,下一小節(jié)會(huì)舉個(gè)例子解釋。
實(shí)際工程如何實(shí)現(xiàn)這些數(shù)據(jù)采集?一般有兩種比較可行的方案:打開所有表掃描一遍,這樣最簡單,而且統(tǒng)計(jì)信息準(zhǔn)確,缺點(diǎn)是對(duì)于大表來說代價(jià)比較大;針對(duì)一些大表,掃描一遍代價(jià)太大,可以采用采樣(sample)的方式統(tǒng)計(jì)計(jì)算。
支持CBO的系統(tǒng)都有命令對(duì)原始數(shù)據(jù)信息進(jìn)行統(tǒng)計(jì),比如Hive的Analyze命令、Impala的Compute命令、Greenplum的Analyze命令等,但是需要注意這些命令并不是隨時(shí)都應(yīng)該執(zhí)行的,首先在表數(shù)據(jù)沒有大變動(dòng)的情況下沒必要執(zhí)行,其次在系統(tǒng)查詢高發(fā)期也不應(yīng)該執(zhí)行。這里有個(gè)最佳實(shí)踐:盡可能在業(yè)務(wù)低峰期對(duì)表數(shù)據(jù)有較大變動(dòng)的表單獨(dú)執(zhí)行統(tǒng)計(jì)命令,這句話有三個(gè)重點(diǎn),不知道你看出來沒有?
第二步:定義核心算子的基數(shù)推導(dǎo)規(guī)則
規(guī)則推導(dǎo)意思是說在當(dāng)前子節(jié)點(diǎn)統(tǒng)計(jì)信息的基礎(chǔ)上,計(jì)算父節(jié)點(diǎn)相關(guān)統(tǒng)計(jì)信息的一套推導(dǎo)規(guī)則。對(duì)于不同算子,推導(dǎo)規(guī)則必然不一樣,比如fliter、group by、limit等等的評(píng)估推導(dǎo)是不同的。這里以filter為例進(jìn)行講解。先來看看這樣一個(gè)SQL:select * from A , C where A.id = C.c_id and C.c_id > N ,經(jīng)過RBO之后的語法樹如下圖所示:
問題定義為:假如現(xiàn)在已經(jīng)知道表C的基本統(tǒng)計(jì)信息(estimatedSize、rowCount、basicStats以及histograms),如何推導(dǎo)出經(jīng)過C.c_id > N過濾后中間結(jié)果的基本統(tǒng)計(jì)信息。我們來看看:
1、假設(shè)已知C列的最小值c_id.Min、最大值c_id.Max以及總行數(shù)c_id.Distinct,同時(shí)假設(shè)數(shù)據(jù)分布均勻,如下圖所示:
2、現(xiàn)在分別有三種情況需要說明,其一是N小于c_id.Min,其二是N大于c_id.Max,其三是N介于c_id.Min和c_id.Max之間。前兩種場景是第三種場景的特殊情況,這里簡單的針對(duì)第三種場景說明。如下圖所示:
在C.c_id > N過濾條件下,c_id.Min會(huì)增大到N,c_id.Max保持不變。而過濾后總行數(shù)c_id.distinct(after filter) = (c_id.Max – N) / (c_id.Max – c_id.Min) * c_id.distinct(before filter)
簡單吧,但是注意哈,上面計(jì)算是在假設(shè)數(shù)據(jù)分布均勻的前提下完成的,而實(shí)際場景中數(shù)據(jù)分布很顯然不可能均衡。數(shù)據(jù)分布通常成概率分布,histograms在這里就要登場了,說白了它就是一個(gè)柱狀分布圖,如下圖:
柱狀圖橫坐標(biāo)表示列值大小分布,縱坐標(biāo)表示頻率。假設(shè)N在如圖所示位置,那過濾后總行數(shù)c_id.distinct(after filter) = height(>N) / height(All) * c_id.distinct(before filter)
當(dāng)然,上述所有計(jì)算都只是示意性計(jì)算,真實(shí)算法會(huì)復(fù)雜很多。另外,如果大家對(duì)group by 、limit等謂詞的評(píng)估規(guī)則比較感興趣的話,可以閱讀SparkSQL CBO設(shè)計(jì)文檔,在此不再贅述。至此,通過各種評(píng)估規(guī)則以及原始表統(tǒng)計(jì)信息就可以計(jì)算出語法樹中所有中間節(jié)點(diǎn)的基本統(tǒng)計(jì)信息了,這是萬里長征的第二步,也是至關(guān)重要的一步。接下來繼續(xù)往前走,看看如何計(jì)算每種核心算子的實(shí)際代價(jià)。
第三步:核心算子實(shí)際代價(jià)計(jì)算
打文章一開始就開口閉口代價(jià)代價(jià)的,可到底什么是代價(jià),怎么定義代價(jià)?這么說吧,每個(gè)系統(tǒng)對(duì)代價(jià)的定義并不非常一致,有的因?yàn)閷?shí)現(xiàn)的原因設(shè)置的比較簡單,有的會(huì)比較復(fù)雜。這一節(jié)主要來簡單聊聊每個(gè)節(jié)點(diǎn)的執(zhí)行代價(jià),上文說了,一條執(zhí)行路徑的總代價(jià)就是這條路徑上所有節(jié)點(diǎn)的代價(jià)累加之和。
通常來講,節(jié)點(diǎn)實(shí)際執(zhí)行代價(jià)主要從兩個(gè)維度來定義:CPU Cost以及IO Cost。為后續(xù)講解方便起見,需要先行定義一些基本參數(shù):
- Hr:從HDFS上讀取1byte數(shù)據(jù)所需代價(jià)
- Hw:往HDFS上寫入1byte數(shù)據(jù)所需代價(jià)
- Tr:數(shù)據(jù)總條數(shù)(the number of tuples in the relation )
- Tsz:數(shù)據(jù)平均大小(Average size of the tuple in the relation )
- CPUc:兩值比較所需CPU資源代價(jià)(CPU cost for a comparison in nano seconds )
- NEt:1byte數(shù)據(jù)通過網(wǎng)絡(luò)在集群節(jié)點(diǎn)間傳輸花費(fèi)代價(jià)(the average cost of transferring 1 byte
over network in the Hadoop cluster from any node to any node ) - ……
- 上文說過,每種算子的實(shí)際執(zhí)行代價(jià)計(jì)算方式都不同,在此不可能列舉所有算子,就挑兩個(gè)比較簡單、容易理解的來分析,第一個(gè)是Table
Scan算子,第二個(gè)是Hash Join算子。
Table Scan算子
Scan算子一般位于語法樹的葉子結(jié)點(diǎn),直觀上來講這類算子只有IO Cost,CPU Cost為0。Table Scan Cost = IO Cost = Tr * Tsz * Hr,很簡單,Tr * Tsz表示需要scan的數(shù)據(jù)總大小,再乘以Hr就是所需代價(jià)。OK,很直觀,很簡單。
Hash Join算子
以Broadcast Hash Join為例(如果看官對(duì)Broadcast Hash Join工作原理還不了解,可戳這里),假設(shè)大表分布在n個(gè)節(jié)點(diǎn)上,每個(gè)節(jié)點(diǎn)的數(shù)據(jù)條數(shù)\平均大小分別為Tr(R1)\Tsz(R1),Tr(R2)\Tsz(R2), … Tr(Rn)\Tsz(Rn),小表數(shù)據(jù)條數(shù)為Tr(Rsmall)\Tsz(Rsmall),那么CPU代價(jià)和IO代價(jià)分別為:
CPU Cost = 小表構(gòu)建Hash Table代價(jià) + 大表探測代價(jià) = Tr(Rsmall) * CPUc + (Tr(R1) + Tr(R2) + … + Tr(Rn)) * N * CPUc,此處假設(shè)HashTable構(gòu)建所需CPU資源遠(yuǎn)遠(yuǎn)高于兩值簡單比較代價(jià),為N * CPUc
IO Cost = 小表scan代價(jià) + 小表廣播代價(jià) + 大表scan代價(jià) = Tr(Rsmall) * Tsz(Rsmall) * Hr + n * Tr(Rsmall) * Tsz(Rsmall) * NEt + (Tr(R1)* Tsz(R1) + … + Tr(Rn) * Tsz(Rn)) * Hr
很顯然,Hash Join算子相比Table Scan算子來講稍稍復(fù)雜了一點(diǎn),但是無論哪種算子,代價(jià)計(jì)算都和參與的數(shù)據(jù)總條數(shù)、數(shù)據(jù)平均大小等因素直接相關(guān),這也就是為什么在之前兩個(gè)步驟中要不懈余力地計(jì)算中間結(jié)果相關(guān)詳細(xì)的真正原因。可謂是步步為營、環(huán)環(huán)相扣。這下好了,任意節(jié)點(diǎn)的實(shí)際代價(jià)都能評(píng)估出來,那么給定任意執(zhí)行路徑的代價(jià)必然也就很簡單嘍。
第四步:選擇最優(yōu)執(zhí)行路徑(代價(jià)最小執(zhí)行路徑)
這個(gè)思路很容易理解的,經(jīng)過上述三步的努力,可以很容易地計(jì)算出任意一條給定路徑的代價(jià)。那么你只需要找出所有可行的執(zhí)行路徑,一個(gè)一個(gè)計(jì)算,就必然能找到一個(gè)代價(jià)最小的,也就是最優(yōu)的執(zhí)行路徑。
這條路看起來確實(shí)很簡單,但實(shí)際做起來卻并不那么容易,為什么?所有可行的執(zhí)行路徑實(shí)在太多,所有路徑都計(jì)算一遍,黃花菜都涼了。那么有什么好的解決方案么?當(dāng)然,其實(shí)看到這個(gè)標(biāo)題-選擇代價(jià)最小執(zhí)行路徑,就應(yīng)該很容易想到-動(dòng)態(tài)規(guī)劃,如果你沒有想到,那只能說明你沒有讀過《數(shù)學(xué)之美》、沒刷過LeetCode、沒玩過ACM,ACM、LeetCode如果覺得太枯燥,那就去看看《數(shù)學(xué)之美》,它會(huì)告訴你從當(dāng)前這個(gè)你所在的地方開車去北京,如何使用動(dòng)態(tài)規(guī)劃選擇一條最短的路線。在此不再贅述。
至此,筆者粗線條地介紹了當(dāng)前主流SQL引擎是如何將CBO這么一個(gè)看似高深的技術(shù)一步一步落地的。接下來,筆者將會(huì)借用Hive、Impala這兩大SQL引擎開啟CBO之后的優(yōu)化效果讓大家對(duì)CBO有一個(gè)更直觀的理解。
Hive – CBO優(yōu)化效果
Hive本身沒有去從頭實(shí)現(xiàn)一個(gè)SQL優(yōu)化器,而是借助于Apache Calcite ,Calcite是一個(gè)開源的、基于CBO的企業(yè)級(jí)SQL查詢優(yōu)化框架,目前包括Hive、Phoniex、Kylin以及Flink等項(xiàng)目都使用了Calcite作為其執(zhí)行優(yōu)化器,這也很好理解,執(zhí)行優(yōu)化器本來就可以抽象成一個(gè)系統(tǒng)模塊,并沒有必要花費(fèi)大量時(shí)間去重復(fù)造輪子。
hortonworks曾經(jīng)對(duì)Hive的CBO特性做了相關(guān)的測試,測試結(jié)果認(rèn)為CBO至少對(duì)查詢有三個(gè)重要的影響:Join ordering optimization、Bushy join support以及Join simplification,本文只簡單介紹一下Join ordering optimization,有興趣的同學(xué)可以繼續(xù)閱讀這篇文章來更多地了解其他兩個(gè)重要影響。(下面數(shù)據(jù)以及示意圖也來自于該篇文章,特此注明)
hortonworks對(duì)TPCDS的部分Query進(jìn)行了研究,發(fā)現(xiàn)對(duì)于大部分星型\雪花模型,都存在多Join問題,這些Join順序如果組織不好,性能就會(huì)很差,如果組織得當(dāng),性能就會(huì)很好。比如Query Q3:
上述Query涉及到3張表,一張事實(shí)表store_sales(數(shù)據(jù)量大)和兩張維度表(數(shù)據(jù)量小),三表之間的關(guān)系如下圖所示:
這里就涉及上文提到的Join順序問題,從原始表來看,date_dim有73049條記錄,而item有462000條記錄。很顯然,如果沒有其他暗示的話,Join順序必然是store_sales join date_dim join item。但是,where條件中還帶有兩個(gè)條件,CBO會(huì)根據(jù)過濾條件對(duì)過濾后的數(shù)據(jù)進(jìn)行評(píng)估,結(jié)果如下:
| date_dim | 73,049 | 6200 | 8.5% |
| item | 462,000 | 484 | 0.1% |
根據(jù)上表所示,過濾后的數(shù)據(jù)量item明顯比date_dim小的多,劇情反轉(zhuǎn)的有點(diǎn)快。于是乎,經(jīng)過CBO之后Join順序就變成了store_sales join item join date_time,為了進(jìn)一步確認(rèn),可以在開啟CBO前后分別記錄該SQL的執(zhí)行計(jì)劃,如下圖所示:
左圖是未開啟CBO特性時(shí)Q3的執(zhí)行計(jì)劃,store_sales先與date_dim進(jìn)行join,join后的中間結(jié)果數(shù)據(jù)集有140億條。而再看右圖,store_sales先于item進(jìn)行join,中間結(jié)果只有8200w條。很顯然,后者執(zhí)行效率會(huì)更高,實(shí)踐出真知,來看看兩者的實(shí)際執(zhí)行時(shí)間:
| Q3 CBO OFF | 255 | 13,987,506,884 | 51,967 |
| Q3 CBO ON | 142 | 86,217,653 | 35,036 |
上圖很明顯的看出Q3在CBO的優(yōu)化下性能將近提升了1倍,與此同時(shí),CPU資源使用率也降低了一半左右。不得不說,TPCDS中有很多相似的Query,有興趣的同學(xué)可以深入進(jìn)一步深入了解。
Impala – CBO優(yōu)化效果
和Hive優(yōu)化的原理相同,也是針對(duì)復(fù)雜join的執(zhí)行順序、Join的執(zhí)行策略選擇優(yōu)化等方面進(jìn)行的優(yōu)化,本人使用TPC-DS對(duì)Impala在開啟CBO特性前后的部分Query進(jìn)行了性能測試,測試結(jié)果如下圖所示:
參考:
http://hbasefly.com/2017/05/04/bigdata%ef%bc%8dcbo/
總結(jié)
以上是生活随笔為你收集整理的SQL中基于代价的优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HCNA每日一练错误
- 下一篇: 使用VMware创建一个虚拟机,并安装乌