hive的優(yōu)化主要分為:配置優(yōu)化缅糟、SQL語句優(yōu)化堵漱、任務(wù)優(yōu)化等方案。
其中在開發(fā)過程中主要涉及到的可能是SQL優(yōu)化這塊莱找。
優(yōu)化的核心思想是:
減少數(shù)據(jù)量(例如分區(qū)酬姆、列剪裁);
避免數(shù)據(jù)傾斜(例如加參數(shù)奥溺、Key打散)辞色;
避免全表掃描(例如on添加加上分區(qū)等);
減少job數(shù)(例如相同的on條件的join放在一起作為一個任務(wù))浮定。
HQL語句優(yōu)化
1相满、使用分區(qū)剪裁、列剪裁
在分區(qū)剪裁中桦卒,當(dāng)使用外關(guān)聯(lián)時立美,如果將副表的過濾條件寫在Where后面,那么就會先全表關(guān)聯(lián)方灾,之后再過濾悯辙。
selecta.*fromtest1aleftjointest2bona.uid=b.uidwherea.ds='2020-08-10'andb.ds='2020-08-10'
上面這個SQL主要是犯了兩個錯誤:
副表的過濾條件寫在where后面,會導(dǎo)致先全表關(guān)聯(lián)在過濾分區(qū)迎吵;
on的條件沒有過濾null值的情況,如果兩個數(shù)據(jù)表存在大批量null值的情況针贬,會造成數(shù)據(jù)傾斜击费。
selecta.*fromtest1aleftjointest2bon(d.uidisnotnullanda.uid=b.uidandb.ds='2020-08-10')wherea.ds='2020-08-10'
如果null值也是需要的,那么需要在條件上轉(zhuǎn)換桦他,或者單獨拿出來
selecta.*fromtest1aleftjointest2bon(a.uidisnotnullanda.uid=b.uidandb.ds='2020-08-10')wherea.ds='2020-08-10'unionallselecta.*fromtest1awherea.uidisnull或者selecta.*fromtest1aleftjointest2boncasewhena.uidisnullthenconcat("test",RAND())elsea.uidend=b.uidandb.ds='2020-08-10'wherea.ds='2020-08-10'或者(子查詢)selecta.*fromtest1aleftjoin(selectuidfromtest2whereds='2020-08-10'anduidisnotnull)bona.uid=b.uidwherea.uidisnotnullanda.ds='2020-08-10'
2蔫巩、盡量不要用COUNT
DISTINCT,因為COUNT DISTINCT操作需要用一個Reduce
Task來完成快压,這一個Reduce需要處理的數(shù)據(jù)量太大圆仔,就會導(dǎo)致整個Job很難完成,一般COUNT DISTINCT使用先GROUP
BY再COUNT的方式替換蔫劣,雖然會多用一個Job來完成坪郭,但在數(shù)據(jù)量大的情況下,這個絕對是值得的脉幢。
selectcount(distinctuid)fromtestwhereds='2020-08-10'anduidisnotnull轉(zhuǎn)換為selectcount(a.uid)from(selectuidfromtestwhereuidisnotnullandds='2020-08-10'groupbyuid)a
3歪沃、使用with
as嗦锐,因為拖慢hive查詢效率出了join產(chǎn)生的shuffle以外,還有一個就是子查詢沪曙,在SQL語句里面盡量減少子查詢奕污。with
as是將語句中用到的子查詢事先提取出來(類似臨時表),使整個查詢當(dāng)中的所有模塊都可以調(diào)用該查詢結(jié)果液走。使用with
as可以避免Hive對不同部分的相同子查詢進(jìn)行重復(fù)計算碳默。
selecta.*fromtest1aleftjointest2bona.uid=b.uidwherea.ds='2020-08-10'andb.ds='2020-08-10'可以轉(zhuǎn)化為withbasselectuidfromtest2whereds='2020-08-10'anduidisnotnullselecta.*fromtest1aleftjoinbona.uid=b.uidwherea.ds='2020-08-10'anda.uidisnotnull
4、大小表的join缘眶,寫有Join操作的查詢語句時有一條原則:應(yīng)該將條目少的表/子查詢放在Join操作符的左邊嘱根。原因是在Join操作的Reduce階段,位于Join操作符左邊的表的內(nèi)容會被加載進(jìn)內(nèi)存磅崭,將條目少的表放在左邊儿子,可以有效減少發(fā)生OOM錯誤的幾率。
但新版的hive已經(jīng)對小表JOIN大表和大表JOIN小表進(jìn)行了優(yōu)化砸喻。小表放在左邊和右邊已經(jīng)沒有明顯區(qū)別柔逼。
不過在做join的過程中通過小表在前可以適當(dāng)?shù)臏p少數(shù)據(jù)量,提高效率割岛。
5愉适、數(shù)據(jù)傾斜,數(shù)據(jù)傾斜的原理都知道癣漆,就是某一個或幾個key占據(jù)了整個數(shù)據(jù)的90%维咸,這樣整個任務(wù)的效率都會被這個key的處理拖慢,同時也可能會因為相同的key會聚合到一起造成內(nèi)存溢出惠爽。
數(shù)據(jù)傾斜只會發(fā)生在shuffle過程中癌蓖。這里給大家羅列一些常用的并且可能會觸發(fā)shuffle操作的算子:distinct、
groupByKey婚肆、reduceByKey租副、aggregateByKey、join较性、cogroup用僧、repartition等。出現(xiàn)數(shù)據(jù)傾斜時赞咙,
可能就是你的代碼中使用了這些算子中的某一個所導(dǎo)致的责循。
hive的數(shù)據(jù)傾斜一般的處理方案:
常見的做法,通過參數(shù)調(diào)優(yōu):sethive.map.aggr=true;sethive.groupby.skewindata=ture;當(dāng)選項設(shè)定為true時攀操,生成的查詢計劃有兩個MapReduce任務(wù)院仿。在第一個MapReduce中,map的輸出結(jié)果集合會隨機(jī)分布到reduce中速和,每個reduce做部分聚合操作意蛀,并輸出結(jié)果耸别。這樣處理的結(jié)果是,相同的GroupByKey有可能分發(fā)到不同的reduce中县钥,從而達(dá)到負(fù)載均衡的目的秀姐;第二個MapReduce任務(wù)再根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照GroupByKey分布到reduce中(這個過程可以保證相同的GroupByKey分布到同一個reduce中),最后完成最終的聚合操作若贮。但是這個處理方案對于我們來說是個黑盒省有,無法把控。一般處理方案是將對應(yīng)的key值打散即可谴麦。例如:selecta.*fromtest1aleftjointest2bona.uid=b.uidwherea.ds='2020-08-10'andb.ds='2020-08-10'如果有90%的key都是null蠢沿,這樣不可避免的出現(xiàn)數(shù)據(jù)傾斜。selecta.uidfromtest1asajoin(selectcasewhenuidisnullthencast(rand(1000000)asint)elseuidfromtest2whereds='2020-08-10')bona.uid=b.uidwherea.ds='2020-08-10'當(dāng)然這種只是理論上的處理方案匾效。正常的方案是null進(jìn)行過濾舷蟀,但是日常情況下不是這中特殊的key。那么在日常需求的情況下如何處理這種數(shù)據(jù)傾斜的情況呢:1面哼、sample采樣野宜,獲取哪些集中的key;2魔策、將集中的key按照一定規(guī)則添加隨機(jī)數(shù)匈子;3、進(jìn)行join闯袒,由于打散了虎敦,所以數(shù)據(jù)傾斜避免了;4政敢、在處理結(jié)果中對之前的添加的隨機(jī)數(shù)進(jìn)行切分其徙,變成原始的數(shù)據(jù);
當(dāng)然這些優(yōu)化都是針對SQL本身的優(yōu)化喷户,還有一些是通過參數(shù)設(shè)置去調(diào)整的擂橘,這里面就不再詳細(xì)描述了。
但是優(yōu)化的核心思想都差不多:
減少數(shù)據(jù)量摩骨;
避免數(shù)據(jù)傾斜;
減少JOB數(shù)朗若;
虛核心點:根據(jù)業(yè)務(wù)邏輯對業(yè)務(wù)實現(xiàn)的整體進(jìn)行優(yōu)化恼五;
虛解決方案:采用presto、impala等專門的查詢引擎哭懈,采用spark計算引擎替換MR/TEZ灾馒;