一.常用參數(shù)
開啟中間結(jié)果壓縮? 對于輸入數(shù)據(jù)量有少許減少,但是cpu開銷增大珠洗,對于單stage任務總體不理想
set hive.exec.compress.intermediate=true;
set mapred.map.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
開啟最終輸出壓縮
set hive.exec.compress.output=true;
mapred.compress.map.output? ?map的輸出是否壓縮
mapred.map.output.compression.codec??map的輸出壓縮方式
mapred.output.compress?reduce的輸出是否壓縮
mapred.output.compression.codecreduce的輸出壓縮方式
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GZipCodec
減少MAP數(shù)量
設置MAP的分割文件大小 set mapred.max.split.size=512000000
增加MR中MARTASK的可使用內(nèi)存內(nèi)存? set mapreduce.map.memory.mb; 以解決MAP時的OOM
map執(zhí)行時間:map任務啟動和初始化的時間+邏輯處理的時間忱屑。
所以 如果小文件過多茵典,可以執(zhí)行set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;在MAP開始前進行小文件合并
調(diào)整reduce參數(shù)的值
set mapred.reduce.tasks = 15;
set hive.exec.reducers.bytes.per.reducer =
一般根據(jù)輸入文件的總大小,用它的estimation函數(shù)來自動計算reduce的個數(shù):reduce個數(shù) = InputFileSize / bytes per reducer
設置并行度
set hive.exec.paralle=true?
set hive.exec.parallel.thread.number=16;
設置mapjoin
set hive.auto.convert.join = true;
set hive.mapjoin.smalltable.filesize = 2500000 ;//刷入內(nèi)存表的大小(字節(jié))?
設置嚴格模式(一般設置成全局級,而非會話級)
set hive.marped.mode=strict
防止用戶執(zhí)行那些可能意想不到的不好的影響的查詢? 分區(qū)表必須指定分區(qū)
開啟動態(tài)分區(qū)排序優(yōu)化 set hive.optimize.sort.dynamic.partition
? 開啟map任務的mapreduce會引入reduce過程狂秘,這樣動態(tài)分區(qū)的那個字段比如日期在傳到reducer時會被排序硕噩。由于分區(qū)字段是排序的假残,因此每個reducer只需要保持一個文件寫入器(file writer)隨時處于打開狀態(tài)(不然每個動態(tài)分區(qū)都需要打開一個寫入器),在收到來自特定分區(qū)的所有行后榴徐,關(guān)閉記錄寫入器(record writer)守问,從而減小內(nèi)存壓力
二、日常sql編寫技巧
1.將大表放后頭
? ? Hive假定查詢中最后的一個表是大表坑资。它會將其它表緩存起來耗帕,然后掃描最后那個表。 因此通常需要將小表放前面袱贮,或者標記哪張表是大表:/*streamtable(table_name) */
2.使用相同的連接鍵
? ? 當對3個或者更多個表進行join連接時仿便,如果每個on子句都使用相同的連接鍵的話,那么只會產(chǎn)生一個MapReduce job。
3.盡量盡早地過濾數(shù)據(jù)
? ? 減少每個階段的數(shù)據(jù)量,對于分區(qū)表要加分區(qū)嗽仪,同時只選擇需要使用到的字段荒勇。
4.盡量原子化操作
? ? 盡量避免一個SQL包含復雜邏輯,可以使用中間表來完成復雜的邏輯
5.limit 語句快速出結(jié)果
? ? 尤其是spark sql
數(shù)據(jù)傾斜
原因
1)闻坚、key分布不均勻
2)沽翔、業(yè)務數(shù)據(jù)本身的特性
3)、建表時考慮不周
4)窿凤、某些SQL語句本身就有數(shù)據(jù)傾斜
解決方案:
場景1:join時小表放在前面仅偎,并開啟mapjoin??? set hive.auto.convert.join = true;
? ? ? ? 或使用?set hive.optimize.skewinfo=table_B:(selleer_id) [ ( "0") ("1") ) ]? ?說明B表的值集中在0和1上
set hive.optimize.skewjoin = true;
場景2:借助隨機函數(shù) 對關(guān)聯(lián)不到的 如0值或空值進行過濾或隨機函數(shù)替換處理,避免傾斜
場景3:方案1:通過 union all將數(shù)據(jù)進行分離雳殊,聚集值單獨處理
? ? ? ? ? ? ?方案2:在MAP端 預聚合 set hive.map.aggr=true
這個設置可以將頂層的聚合操作放在Map階段執(zhí)行橘沥,從而減輕清洗階段數(shù)據(jù)傳輸和Reduce階段的執(zhí)行時間,提升總體性能夯秃。確點是更廢內(nèi)存
? ? ? ? ? ? ?方案3:? ? 1.hive.groupby.skewindata=true? (set hive.groupby.mapaggr.checkinterval=100000;這個是group的鍵對應的記錄條數(shù)超過這個值則會進行優(yōu)化? 注意:該參數(shù)僅支持單列
hive.groupby.skewindata=true 控制生成兩個MR Job座咆。
第一個MRJob 中,Map的輸出結(jié)果集合會隨機分布到Reduce中仓洼,每個Reduce做部分聚合操作介陶,并輸出結(jié)果,這樣處理的結(jié)果是相同的GroupBy Key有可能被分發(fā)到不同的Reduce中衬潦,從而達到負載均衡的目的斤蔓;第二個MRJob再根據(jù)預處理的數(shù)據(jù)結(jié)果按照GroupBy Key分布到Reduce中(這個過程可以保證相同的GroupBy Key被分布到同一個Reduce中
場景4:?select count(distinct udid) from T 改寫成? select count(1) from( select distinct udid from T) t;
區(qū)別:增加一個JOB植酥,同時后者在執(zhí)行子查詢的時候镀岛,可以有多個reduce參與計算,而前者只有一個reduce
大表JOIN大表時性能問題
1.分桶
建表時采用表分桶的設計友驮,同時join時可以嘗試使用bucket map join漂羊;基本處理方法是將兩個表在join key上做hash bucket,將較小表(sale_history)的bucket設置為較大表(call_result)的數(shù)倍卸留。這樣數(shù)據(jù)就會按照join key做hash bucket走越。這樣做的話,小表依然會復制到各個節(jié)點上耻瑟,map join的時候旨指,小表的每一組bucket加載成hashtable,與對應的大表bucket做局部join喳整。
如果兩表的join key 都具有唯一性(是主鍵關(guān)聯(lián))谆构,還可以進一步做sort merge bucket map join ;做法是兩表都做bucket的基礎(chǔ)上框都,每個bucket內(nèi)部還要進行排序搬素,這樣做得好處就是在兩邊的bucket要做局部join的時候,用類似merge sort算法中的merge操作一樣把兩個bucket順序遍歷一下即可。
1.1 條件
1) set hive.optimize.bucketmapjoin = true;
2) 一個表的bucket數(shù)是另一個表bucket數(shù)的整數(shù)倍
3) bucket列 == join列
4) 必須是應用在map join的場景中
1.2 注意
1)如果表不是bucket的熬尺,只是做普通join
2.業(yè)務場景處理:
? ? ? ?看懂實現(xiàn)邏輯即可摸屠,核心邏輯,無外乎是維護一個大客戶表粱哼,對數(shù)據(jù)進行放大季二,結(jié)合隨機函數(shù),生成新的關(guān)聯(lián)鍵揭措,確保只關(guān)聯(lián)到其中的一條即可戒傻,將數(shù)據(jù)的集中度進行打散
1).通用方案
此方案的思路是建立一個numbers表,其值只有一列int 行蜂筹,比如從1到10(具體值可根據(jù)傾斜程度確定)需纳,然后放大B表10倍,再取模join艺挪。代碼如下:
select
m.buyer_id,
sum(pay_cnt_90day)? as pay_cnt_90day,
sum(case when m.sale_level = 0? then pay_cnt_90day? end)? as pay_cnt_90day_s0,
sum(case when m.sale_level = 1? then pay_cnt_90day? end)? as pay_cnt_90day_s1,
sum(case when m.sale_level = 2? then pay_cnt_90day? end)? as pay_cnt_90day_s2,
sum(case when m.sale_level = 3? then pay_cnt_90day? end)? as pay_cnt_90day_s3,
sum(case when m.sale_level = 4? then pay_cnt_90day? end)? as pay_cnt_90day_s4,
sum(case when m.sale_level = 5? then pay_cnt_90day? end)? as pay_cnt_90day_s5
from?(
select??a.buer_id,? a.seller_id,? b.sale_level, a.pay_cnt_90day
from?(??select buyer_id,? seller_id,? pay_cnt_90day? ?from table_A)? a
join
? ? ? ?(
select? /*+mapjoin(members)*/
seller_id,? sale_level ,member
from table_B
? ? join members
)? b
on? a.seller_id? = b.seller_id
and mod(a.pay_cnt_90day,10)+1 = b.number?
)? m
group by?m.buyer_id
? 此思路的核心在于不翩,既然按照seller_id分發(fā)會傾斜,那么再人工增加一列進行分發(fā)麻裳,這樣之前傾斜的值的傾斜程度會減少到原來的1/10口蝠,可以通過配置numbers表改放大倍數(shù)來降低傾斜程度,
但這樣做的一個弊端是B表也會膨脹N倍津坑。
2).專用方案
通用方案的思路把B表的每條數(shù)據(jù)都放大了相同的倍數(shù)妙蔗,實際上這是不需要的,只需要把大賣家放大倍數(shù)即可:需要首先知道大賣家的名單疆瑰,即先建立一個臨時表動態(tài)存放每天最新的大賣家(
比如dim_big_seller),同時此表的大賣家要膨脹預先設定的倍數(shù)(1000倍)眉反。
在A表和B表分別新建一個join列,其邏輯為:如果是大賣家穆役,那么concat一個隨機分配正整數(shù)(0到預定義的倍數(shù)之間寸五,本例為0~1000);如果不是耿币,保持不變梳杏。具體代碼如下:
select
m.buyer_id,
sum(pay_cnt_90day)? as pay_cnt_90day,
sum(case when m.sale_level = 0? then pay_cnt_90day? end)? as pay_cnt_90day_s0,
sum(case when m.sale_level = 1? then pay_cnt_90day? end)? as pay_cnt_90day_s1,
sum(case when m.sale_level = 2? then pay_cnt_90day? end)? as pay_cnt_90day_s2,
sum(case when m.sale_level = 3? then pay_cnt_90day? end)? as pay_cnt_90day_s3,
sum(case when m.sale_level = 4? then pay_cnt_90day? end)? as pay_cnt_90day_s4,
sum(case when m.sale_level = 5? then pay_cnt_90day? end)? as pay_cnt_90day_s5
from?(
select??a.buer_id,? a.seller_id,? b.sale_level, a.pay_cnt_90day
from?(??
select??/*+mapjoin(big)*/
buyer_id,? seller_id,? pay_cnt_90day,
if(big.seller_id is not null, concat(? table_A.seller_id,? 'rnd',? cast(? rand() * 1000 as bigint ), table_A.seller_id)? as seller_id_joinkey
??from table_A
? ?left outer join
--big表seller_id有重復,請注意一定要group by 后再join,保證table_A的行數(shù)保持不變
⊙徒印(select seller_id? from dim_big_seller? group by seller_id)big
on table_A.seller_id = big.seller_id
)? a
join
? ? ? ?(
select? /*+mapjoin(big)*/
seller_id,? sale_level ,
--big表的seller_id_joinkey生成邏輯和上面的生成邏輯一樣
coalesce(seller_id_joinkey,table_B.seller_id) as seller_id_joinkey
from table_B
? ? left out join
--table_B表join大賣家表后大賣家行數(shù)擴大1000倍十性,其它賣家行數(shù)保持不變
(select seller_id, seller_id_joinkey from dim_big_seller) big
on table_B.seller_id= big.seller_id
)? b
on? a.seller_id_joinkey= b.seller_id_joinkey
)? m
group by?m.buyer_id
相比通用方案,專用方案的運行效率明細好了許多塑悼,因為只是將B表中大賣家的行數(shù)放大了1000倍劲适,其它賣家的行數(shù)保持不變,但同時代碼復雜了很多拢肆,而且必須首先建立大數(shù)據(jù)表减响。
3).動態(tài)一分為二
實際上方案2和3都用了一分為二的思想靖诗,但是都不徹底,對于mapjoin不能解決的問題支示,終極解決方案是動態(tài)一分為二刊橘,即對傾斜的鍵值和不傾斜的鍵值分開處理,不傾斜的正常join即可颂鸿,
傾斜的把他們找出來做mapjoin,最后union all其結(jié)果即可促绵。
但是此種解決方案比較麻煩,代碼復雜而且需要一個臨時表存放傾斜的鍵值嘴纺。代碼如下:
--由于數(shù)據(jù)傾斜败晴,先找出90天買家超過10000的賣家
insert overwrite table? temp_table_B
select?
m.seller_id,? n.sale_level
from (
select? ?seller_id
from (
select seller_id,count(buyer_id) as byr_cnt
from table_A
group by seller_id
) a
where a.byr_cnt >10000
) m
left join?
(
select seller_id, sale_level? from table_B
) n
? ?on m.seller_id = n.seller_id;
--對于90天買家超過10000的賣家直接mapjoin,對其它賣家直接正常join即可。
大表關(guān)聯(lián)案例? 引用自? https://www.cnblogs.com/shaosks/p/9491905.html