1、數(shù)據(jù)傾斜優(yōu)化
數(shù)據(jù)傾斜問題,通常是指參與計算的數(shù)據(jù)分布不均,即某個key或者某些key的數(shù)據(jù)量遠超其他key,導致在shuffle階段,大量相同key的數(shù)據(jù)被發(fā)往同一個Reduce,進而導致該Reduce所需的時間遠超其他Reduce,成為整個任務的瓶頸。
比如對于一張表的province_id字段,其中99%的值都為1,則進行hash分區(qū)的時候,都會放到一個reduce上,運行效率降低,發(fā)生數(shù)據(jù)傾斜。
Hive中的數(shù)據(jù)傾斜常出現(xiàn)在分組聚合和join操作的場景中,下面分別介紹在上述兩種場景下的優(yōu)化思路。
1.1 由分組聚合導致的數(shù)據(jù)傾斜
(1)優(yōu)化說明
Hive中未經(jīng)優(yōu)化的分組聚合,是通過一個MapReduce Job實現(xiàn)的。Map端負責讀取數(shù)據(jù),并按照分組字段分區(qū),通過Shuffle,將數(shù)據(jù)發(fā)往Reduce端,各組數(shù)據(jù)在Reduce端完成最終的聚合運算。
如果group by分組字段的值分布不均,就可能導致大量相同的key進入同一Reduce,從而導致數(shù)據(jù)傾斜問題。
由分組聚合導致的數(shù)據(jù)傾斜問題,有以下兩種解決思路:
1)Map-Side聚合
開啟Map-Side聚合后,數(shù)據(jù)會現(xiàn)在Map端完成部分聚合工作。這樣一來即便原始數(shù)據(jù)是傾斜的,經(jīng)過Map端的初步聚合后,發(fā)往Reduce的數(shù)據(jù)也就不再傾斜了。最佳狀態(tài)下,Map-端聚合能完全屏蔽數(shù)據(jù)傾斜問題。
相關參數(shù)如下:
--啟用map-side聚合
set hive.map.aggr=true;
--用于檢測源表數(shù)據(jù)是否適合進行map-side聚合。檢測的方法是:先對若干條數(shù)據(jù)進行map-side聚合,若聚合后的條數(shù)和聚合前的條數(shù)比值小于該值,則認為該表適合進行map-side聚合;否則,認為該表數(shù)據(jù)不適合進行map-side聚合,后續(xù)數(shù)據(jù)便不再進行map-side聚合。
set hive.map.aggr.hash.min.reduction=0.5;
--用于檢測源表是否適合map-side聚合的條數(shù)。
set hive.groupby.mapaggr.checkinterval=100000;
--map-side聚合所用的hash table,占用map task堆內(nèi)存的最大比例,若超出該值,則會對hash table進行一次flush。
set hive.map.aggr.hash.force.flush.memory.threshold=0.9;
2)Skew-GroupBy優(yōu)化(Skew指的是數(shù)據(jù)傾斜)
- Skew-GroupBy是hive提供的專門用于解決分組聚合導致的數(shù)據(jù)傾斜的一個方案。
Skew-GroupBy的原理是啟動兩個MR任務,第一個MR按照隨機數(shù)分區(qū),將數(shù)據(jù)分散發(fā)送到Reduce,完成部分聚合,第二個MR按照分組字段分區(qū),完成最終聚合。
相關參數(shù)如下:
--啟用分組聚合數(shù)據(jù)傾斜優(yōu)化
set hive.groupby.skewindata=true;
(2)優(yōu)化案例
1)示例SQL語句
hive (default)>
select
province_id,
count(*)
from order_detail
group by province_id;
2)優(yōu)化前
該表數(shù)據(jù)中的province_id字段是存在傾斜的,若不經(jīng)過優(yōu)化,通過觀察任務的執(zhí)行過程,是能夠看出數(shù)據(jù)傾斜現(xiàn)象的。
需要注意的是,hive中的map-side聚合是默認開啟的,若想看到數(shù)據(jù)傾斜的現(xiàn)象,需要先將hive.map.aggr參數(shù)設置為false。
--優(yōu)化前
set hive.map.aggr=false;
set hive.groupby.skewindata=false
3)優(yōu)化思路
通過上述兩種思路均可解決數(shù)據(jù)傾斜的問題。下面分別進行說明:
(1)方案一:Map-Side聚合
設置如下參數(shù)
1、啟用map-side聚合
set hive.map.aggr=true;
2、關閉skew-groupby
set hive.groupby.skewindata=false;
開啟map-side聚合后的執(zhí)行計劃如下圖所示:
開啟map-side聚合后,reduce數(shù)據(jù)不再傾斜。
(2)方案二:Skew-GroupBy優(yōu)化
設置如下參數(shù):
·1、啟用skew-groupby
set hive.groupby.skewindata=true;
2、關閉map-side聚合
set hive.map.aggr=false;
開啟Skew-GroupBy優(yōu)化后,可以很明顯看到該sql執(zhí)行在yarn上啟動了兩個mr任務,第一個mr打散數(shù)據(jù),第二個mr按照打散后的數(shù)據(jù)進行分組聚合。
小結:
- 對比方案一和方案二,發(fā)現(xiàn)方案一的運行時間更短,因為方案一使用map端聚合,相比于方案二少一個MR,并且方案一充分的利用內(nèi)存去進行聚合,這個速度比跑兩個MR要快,
1.2 join導致的數(shù)據(jù)傾斜
(1)優(yōu)化說明
前文提到過,未經(jīng)優(yōu)化的join操作,默認是使用common join算法,也就是通過一個MapReduce Job完成計算。Map端負責讀取join操作所需表的數(shù)據(jù),并按照關聯(lián)字段進行分區(qū),通過Shuffle,將其發(fā)送到Reduce端,相同key的數(shù)據(jù)在Reduce端完成最終的Join操作。
如果關聯(lián)字段的值分布不均,就可能導致大量相同的key進入同一Reduce,從而導致數(shù)據(jù)傾斜問題。
由join導致的數(shù)據(jù)傾斜問題,有如下三種解決方案:
方案一:map join
使用map join算法,join操作僅在map端就能完成,沒有shuffle操作,沒有reduce階段,自然不會產(chǎn)生reduce端的數(shù)據(jù)傾斜。該方案適用于大表join小表時發(fā)生數(shù)據(jù)傾斜的場景。
相關參數(shù)如下:
--啟動Map Join自動轉(zhuǎn)換
set hive.auto.convert.join=true;
--一個Common Join operator轉(zhuǎn)為Map Join operator的判斷條件,若該Common Join相關的表中,存在n-1張表的大小總和<=該值,則生成一個Map Join計劃,此時可能存在多種n-1張表的組合均滿足該條件,則hive會為每種滿足條件的組合均生成一個Map Join計劃,同時還會保留原有的Common Join計劃作為后備(back up)計劃,實際運行時,優(yōu)先執(zhí)行Map Join計劃,若不能執(zhí)行成功,則啟動Common Join后備計劃。
set hive.mapjoin.smalltable.filesize=250000;
--開啟無條件轉(zhuǎn)Map Join
set hive.auto.convert.join.noconditionaltask=true;
--無條件轉(zhuǎn)Map Join時的小表之和閾值,若一個Common Join operator相關的表中,存在n-1張表的大小總和<=該值,此時hive便不會再為每種n-1張表的組合均生成Map Join計劃,同時也不會保留Common Join作為后備計劃。而是只生成一個最優(yōu)的Map Join計劃。
set hive.auto.convert.join.noconditionaltask.size=10000000;
方案二:skew join
- 因為map join只能解決大表join小表的數(shù)據(jù)傾斜問題,如果是大表join大表,并且有一張表是存在數(shù)據(jù)傾斜的,則使用skew join。(不能使用bucket map join,因為這樣分桶出來的每個桶里的數(shù)據(jù)也是傾斜的)
skew join的原理是:==為傾斜的大key單獨啟動一個map join任務進行計算,其余key進行正常的common join。==原理圖如下:
相關參數(shù)如下:
1、啟用skew join優(yōu)化
set hive.optimize.skewjoin=true;
2、觸發(fā)skew join的閾值,若某個key的行數(shù)超過該參數(shù)值,則觸發(fā)
set hive.skewjoin.key=100000;
- 如果一個key的數(shù)據(jù)超過十萬行,則hive會認為這是一個傾斜的大key,就會單獨啟動一個map join。
這種方案對參與join的源表大小沒有要求,但是對兩表中傾斜的key的數(shù)據(jù)量有要求,要求一張表中的傾斜key的數(shù)據(jù)量比較?。ǚ奖阕適apjoin)。
方案三:調(diào)整SQL語句
若參與join的兩表均為大表,其中一張表的數(shù)據(jù)是傾斜的,此時也可通過以下方式對SQL語句進行相應的調(diào)整。
假設原始SQL語句如下:A,B兩表均為大表,且其中一張表的數(shù)據(jù)是傾斜的。
hive (default)>
select
*
from A
join B
on A.id=B.id;
其join過程如下:
圖中1001為傾斜的大key,可以看到,其被發(fā)往了同一個Reduce進行處理。
調(diào)整SQL語句如下:
hive (default)>
select
*
from(
select --打散操作
concat(id,'_',cast(rand()*2 as int)) id,
value
from A
)ta
join(
select --擴容操作
concat(id,'_',0) id,
value
from B
union all
select
concat(id,'_',1) id,
value
from B
)tb
on ta.id=tb.id;
調(diào)整之后的SQL語句執(zhí)行計劃如下圖所示:
(2)優(yōu)化案例
1)示例SQL語句
hive (default)>
select
*
from order_detail od
join province_info pi
on od.province_id=pi.id;
2)優(yōu)化前
order_detail表中的province_id字段是存在傾斜的,若不經(jīng)過優(yōu)化,通過觀察任務的執(zhí)行過程,是能夠看出數(shù)據(jù)傾斜現(xiàn)象的。
需要注意的是,hive中的map join自動轉(zhuǎn)換是默認開啟的,若想看到數(shù)據(jù)傾斜的現(xiàn)象,需要先將hive.auto.convert.join參數(shù)設置為false。
3)優(yōu)化思路
上述兩種優(yōu)化思路均可解決該數(shù)據(jù)傾斜問題,下面分別進行說明:
(1)map join
設置如下參數(shù):
1、啟用map join(該參數(shù)默認開啟)
set hive.auto.convert.join=true;
2、關閉skew join(該參數(shù)默認關閉)
set hive.optimize.skewjoin=false;
可以很明顯看到開啟map join以后,mr任務只有map階段,沒有reduce階段,自然也就不會有數(shù)據(jù)傾斜發(fā)生。
(2)skew join
設置如下參數(shù)
1、啟動skew join
set hive.optimize.skewjoin=true;
2、關閉map join
set hive.auto.convert.join=false;
開啟skew join后,使用explain可以很明顯看到執(zhí)行計劃如下圖所示,說明skew join生效,任務既有common join,又有部分key走了map join。
并且該sql在yarn上最終啟動了兩個mr任務,而且第二個任務只有map沒有reduce階段,說明第二個任務是對傾斜的key進行了map join。
2、HQL語法優(yōu)化之任務并行度
對于一個分布式的計算任務而言,設置一個合適的并行度十分重要。Hive的計算任務由MapReduce完成,故并行度的調(diào)整需要分為Map端和Reduce端。
2.1 Map端并行度
Map端的并行度,也就是Map的個數(shù)。是由輸入文件的切片數(shù)決定的。一般情況下,Map端的并行度無需手動調(diào)整。
以下特殊情況可考慮調(diào)整map端并行度:
1)查詢的表中存在大量小文件
按照Hadoop默認的切片策略,一個小文件會單獨啟動一個map task負責計算。若查詢的表中存在大量小文件,則會啟動大量map task,造成計算資源的浪費。這種情況下,可以使用Hive提供的CombineHiveInputFormat
,多個小文件合并為一個切片,從而控制map task個數(shù)。
相關參數(shù)如下:
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
2)map端有復雜的查詢邏輯
若SQL語句中有正則替換、json解析等復雜耗時的查詢邏輯時,map端的計算會相對慢一些。若想加快計算速度,在計算資源充足的情況下,可考慮增大map端的并行度,令map task多一些,每個map task計算的數(shù)據(jù)少一些。相關參數(shù)如下:
一個切片的最大值
set mapreduce.input.fileinputformat.split.maxsize=256000000;
2.2 Reduce端并行度
Reduce端的并行度,也就是Reduce個數(shù)。相對來說,更需要關注。Reduce端的并行度,可由用戶自己指定,也可由Hive自行根據(jù)該MR Job輸入的文件大小進行估算。
Reduce端的并行度的相關參數(shù)如下:
1、指定Reduce端并行度,默認值為-1,表示用戶未指定
set mapreduce.job.reduces;
2、Reduce端并行度最大值
set hive.exec.reducers.max;
3、單個Reduce Task計算的數(shù)據(jù)量,用于估算Reduce并行度
set hive.exec.reducers.bytes.per.reducer;
Reduce端并行度的確定邏輯如下:
若指定參數(shù)mapreduce.job.reduces的值為一個非負整數(shù),則Reduce并行度為指定值。否則,Hive自行估算Reduce并行度,估算邏輯如下:
-
假設Job輸入的文件大小為totalInputBytes
-
參數(shù)hive.exec.reducers.bytes.per.reducer的值為bytesPerReducer。
-
參數(shù)hive.exec.reducers.max的值為maxReducers。
則Reduce端的并行度為:
根據(jù)上述描述,可以看出,Hive自行估算Reduce并行度時,是以整個MR Job輸入的文件大小作為依據(jù)的。因此,在某些情況下其估計的并行度很可能并不準確,此時就需要用戶根據(jù)實際情況來指定Reduce并行度了。
3、HQL語法優(yōu)化之小文件合并
小文件合并優(yōu)化,分為兩個方面,分別是Map端輸入的小文件合并,和Reduce端輸出的小文件合并。
3.1 Map端輸入文件合并
合并Map端輸入的小文件,是指將多個小文件劃分到一個切片中,進而由一個Map Task去處理。目的是防止為單個小文件啟動一個Map Task,浪費計算資源。
相關參數(shù)為:
可將多個小文件切片,合并為一個切片,進而由一個map任務處理
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
3.2 Reduce輸出文件合并
合并Reduce端輸出的小文件,是指將多個小文件合并成大文件。目的是減少HDFS小文件數(shù)量。其原理是根據(jù)計算任務輸出文件的平均大小進行判斷,若符合條件,則單獨啟動一個額外的任務進行合并。
相關參數(shù)為:
1、開啟合并map only任務輸出的小文件
set hive.merge.mapfiles=true;
2、開啟合并map reduce任務輸出的小文件
set hive.merge.mapredfiles=true;
3、合并后的文件大小
set hive.merge.size.per.task=256000000;
4、觸發(fā)小文件合并任務的閾值,若某計算任務輸出的文件平均大小低于該值,則觸發(fā)合并
set hive.merge.smallfiles.avgsize=16000000;
4、其他優(yōu)化
4.1 CBO優(yōu)化
CBO是指Cost based Optimizer,即基于計算成本的優(yōu)化。
在Hive中,計算成本模型考慮到了:數(shù)據(jù)的行數(shù)、CPU、本地IO、HDFS IO、網(wǎng)絡IO等方面。Hive會計算同一SQL語句的不同執(zhí)行計劃的計算成本,并選出成本最低的執(zhí)行計劃。目前CBO在hive的MR引擎下主要用于join的優(yōu)化,例如多表join的join順序。
相關參數(shù)為:
是否啟用cbo優(yōu)化
set hive.cbo.enable=true;
案例:
1)示例SQL語句
hive (default)>
select
*
from order_detail od
join product_info product on od.product_id=product.id
join province_info province on od.province_id=province.id;
2)關閉CBO優(yōu)化
關閉cbo優(yōu)化
set hive.cbo.enable=false;
為了測試效果更加直觀,關閉map join自動轉(zhuǎn)換
set hive.auto.convert.join=false;
根據(jù)執(zhí)行計劃,可以看出,三張表的join順序如下:
3)開啟CBO優(yōu)化
1、開啟cbo優(yōu)化
set hive.cbo.enable=true;
2、為了測試效果更加直觀,關閉map join自動轉(zhuǎn)換
set hive.auto.convert.join=false;
根據(jù)執(zhí)行計劃,可以看出,三張表的join順序如下:
4)總結
根據(jù)上述案例可以看出,CBO優(yōu)化對于執(zhí)行計劃中join順序是有影響的,其之所以會將province_info的join順序提前,是因為province info的數(shù)據(jù)量較小,將其提前,會有更大的概率使得中間結果的數(shù)據(jù)量變小,從而使整個計算任務的數(shù)據(jù)量減小,也就是使計算成本變小。
4.2 謂詞下推
謂詞下推(predicate pushdown)是指,在不影響結果的前提下,盡量將where過濾操作前移,以減少后續(xù)計算步驟的數(shù)據(jù)量。這個過濾指的是where過濾。
相關參數(shù)為:
1、是否啟動謂詞下推(predicate pushdown)優(yōu)化
set hive.optimize.ppd = true;
需要注意的是:
CBO優(yōu)化也會完成一部分的謂詞下推優(yōu)化工作,因為在執(zhí)行計劃中,謂詞越靠前,整個計劃的計算成本就會越低。
4.3 矢量化查詢
Hive的矢量化查詢優(yōu)化,依賴于CPU的矢量化計算,CPU的矢量化計算的基本原理如下圖:
Hive的矢量化查詢,可以極大的提高一些典型查詢場景(例如scans, filters, aggregates, and joins)下的CPU使用效率。
相關參數(shù)如下:
set hive.vectorized.execution.enabled=true;
若執(zhí)行計劃中,出現(xiàn)“Execution mode: vectorized”字樣,即表明使用了矢量化計算。
4.4 Fetch抓取
Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計算。例如:select * from emp;
在這種情況下,Hive可以簡單地讀取emp對應的存儲目錄下的文件,然后輸出查詢結果到控制臺。
相關參數(shù)如下:
- 是否在特定場景轉(zhuǎn)換為fetch 任務:
1、設置為none表示不轉(zhuǎn)換
2、設置為minimal表示支持select *,分區(qū)字段過濾,Limit等
3、設置為more表示支持select 任意字段,包括函數(shù),過濾,和limit等
set hive.fetch.task.conversion=more;
4.5 本地模式
大多數(shù)的Hadoop Job是需要Hadoop提供的完整的可擴展性來處理大數(shù)據(jù)集的。不過,有時Hive的輸入數(shù)據(jù)量是非常小的。在這種情況下,為查詢觸發(fā)執(zhí)行任務消耗的時間可能會比實際job的執(zhí)行時間要多的多。對于大多數(shù)這種情況,Hive可以通過本地模式在單臺機器上處理所有的任務。對于小數(shù)據(jù)集,執(zhí)行時間可以明顯被縮短。
相關參數(shù)如下:
1、開啟自動轉(zhuǎn)換為本地模式
set hive.exec.mode.local.auto=true;
2、設置local MapReduce的最大輸入數(shù)據(jù)量,當輸入數(shù)據(jù)量小于這個值時采用local MapReduce的方式,默認為134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
3、設置local MapReduce的最大輸入文件個數(shù),當輸入文件個數(shù)小于這個值時采用local MapReduce的方式,默認為4
set hive.exec.mode.local.auto.input.files.max=10;
4.6 并行執(zhí)行
Hive會將一個SQL語句轉(zhuǎn)化成一個或者多個Stage,每個Stage對應一個MR Job。默認情況下,Hive同時只會執(zhí)行一個Stage。但是某SQL語句可能會包含多個Stage,但這多個Stage可能并非完全互相依賴,也就是說有些Stage是可以并行執(zhí)行的。此處提到的并行執(zhí)行就是指這些Stage的并行執(zhí)行。相關參數(shù)如下:
1、啟用并行執(zhí)行優(yōu)化
set hive.exec.parallel=true;
2、同一個sql允許最大并行度,默認為8
set hive.exec.parallel.thread.number=8;
4.7 嚴格模式
Hive可以通過設置某些參數(shù)防止危險操作:
1)分區(qū)表不使用分區(qū)過濾
將hive.strict.checks.no.partition.filter設置為true時,對于分區(qū)表,除非where語句中含有分區(qū)字段過濾條件來限制范圍,否則不允許執(zhí)行。換句話說,就是用戶不允許掃描所有分區(qū)。進行這個限制的原因是,通常分區(qū)表都擁有非常大的數(shù)據(jù)集,而且數(shù)據(jù)增加迅速。沒有進行分區(qū)限制的查詢可能會消耗令人不可接受的巨大資源來處理這個表。
2)使用order by沒有l(wèi)imit過濾
將hive.strict.checks.orderby.no.limit設置為true時,==對于使用了order by語句的查詢,要求必須使用limit語句。==因為order by為了執(zhí)行排序過程會將所有的結果數(shù)據(jù)分發(fā)到同一個Reduce中進行處理,強制要求用戶增加這個limit語句可以防止Reduce額外執(zhí)行很長一段時間(開啟了limit可以在數(shù)據(jù)進入到Reduce之前就減少一部分數(shù)據(jù))。
3)笛卡爾積文章來源:http://www.zghlxwxcb.cn/news/detail-794436.html
將hive.strict.checks.cartesian.product設置為true時,會限制笛卡爾積的查詢。 對關系型數(shù)據(jù)庫非常了解的用戶可能期望在執(zhí)行JOIN查詢的時候不使用ON語句而是使用where語句,這樣關系數(shù)據(jù)庫的執(zhí)行優(yōu)化器就可以高效地將WHERE語句轉(zhuǎn)化成那個ON語句。不幸的是,Hive并不會執(zhí)行這種優(yōu)化,因此,如果表足夠大,那么這個查詢就會出現(xiàn)不可控的情況。文章來源地址http://www.zghlxwxcb.cn/news/detail-794436.html
到了這里,關于【Hive_06】企業(yè)調(diào)優(yōu)2(數(shù)據(jù)傾斜優(yōu)化、HQL優(yōu)化等)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!