1. 什么是數(shù)據(jù)傾斜, 如何處理
-
什么是數(shù)據(jù)傾斜
大量相同的key被partition到一臺機器, 造成這臺機器計算任務量極大, 而其他機器計算量任務極小 -
即使數(shù)據(jù)傾斜, UDAF函數(shù)也可能不產(chǎn)生效率低下的問題?
像sum, max, min, count等UDAF不怕數(shù)據(jù)傾斜, 因為會在map端進行一次數(shù)據(jù)聚合 -
count(distinct)最受數(shù)據(jù)傾斜影響?
因為count(distinct)要先按照group by分組, 再按distinct排序. 不會產(chǎn)生map端的聚合. 一般這中語句是很傾斜的;
比如男uv,女uv,淘寶一天30億的pv,如果按性別分組,分配2個reduce,每個reduce處理15億數(shù)據(jù)。 -
如何處理
- key上加上隨機數(shù)打散, 然后最后計算結果時恢復成原來的key
- 過濾空值, 或者將空值變成一個字符串并加上隨機前綴, 由于隨機的key找不到相同的而執(zhí)行失敗
- 將傾斜的key拿出來單獨處理, 最后和其它結果union all在一起(不去重不排序)
- 開啟參數(shù)
hive.groupby.skewindata=true
這會生成2個任務:- 第一個任務: map的輸出結果隨機的分配到reduce上, 每個reduce按照key做第一次聚合
- 第二個任務: 將相同的key分布到同一個partition上, 再做第二次聚合
- 將
count(distinct)替換成sum() group by
2. 如何調(diào)整mapper個數(shù)
mapper個數(shù)受一系列參數(shù)的影響, 最終由這些參數(shù)計算出一個表達式
-
mapred.map.tasks: map任務的期望值, 默認為2 -
default_mapper_num: 通過1個mapper處理1個block塊的數(shù)據(jù), 來計算一個mapper個數(shù)total_input_size : 輸入文件的總大小 dfs.block.size : hdfs一個block塊的大小 default_mapper_num : 為2個參數(shù)的商 -
splitNumber: 通過把一個block塊劃分多個split, 每個mapper處理一個split的方式計算mapper個數(shù)mapred.min.split.size : split的最小size(默認值1B) mapred.max.split.size : split的最大size(默認值64MB) split_size = max(mapred.min.split.size, min(mapred.max.split.size, dfs.block.size)); split_num = total_input_size / split_size
因此 :
- 只有把
mapred.min.split.size的值設置的比dfs.block.size大, 才能達到1個mapper讀取大于1個block塊的目的 - 只有把
mapred.max.split.size設置的比dfs.block.size小, 才能達到1個block塊被多個mapper處理的目的 .
最終得到mapper的個數(shù)計算公式為:
由于 mapred.max.split.size默認為64M, 所以Hive每個map任務默認處理64M的數(shù)據(jù)(1個split)
3. 如何調(diào)整reduce個數(shù)
reducer的個數(shù), 決定了job最后生成的文件個數(shù), 這個數(shù)可以被用戶直接指定; 若沒有指定, hive會通過一個公司計算出來
- mapred.reduce.tasks : 直接指定reducer個數(shù)
- 公式推算
hive.exec.reducers.bytes.per.reducer : 每個reducer處理的最大數(shù)據(jù)量 hive.exec.reducers.max : 最大的reducer個數(shù) 最終計算得出reducer_num = MIN(total_input_size / reducers.bytes.per.reducer, reducers.max)
4. 什么時候需要合并文件
- 什么時候會出現(xiàn)小文件
- 動態(tài)分區(qū)插入數(shù)據(jù),產(chǎn)生大量的小文件,從而導致map數(shù)量劇增。
- reducer數(shù)量太多
- 數(shù)據(jù)源本身就包含大量的小文件
- 輸入時合并文件 : 通過控制split大小控制mapper個數(shù)
mapred.min.split.size : split的最小size(默認值1B) mapred.max.split.size=256000000; mapred.min.split.size.per.node=100000000 : 一個交換機下split的至少的大小(這個值決定了多個交換機上的文件是否需要合并) mapred.min.split.size.per.rack=100000000 : 執(zhí)行Map前進行小文件合并(100M) - 輸出合并文件控制 :
hive.merge.mapfiles : 設置為true, 在mapped-only任務的輸出進行合并 hive.merge.mapredfiles : 設置為true, 在map-reduce任務的輸出進行合并 hive.merge.size.smallfiles.avgsize : 指定輸出文件的均值大小, 當輸出文件小于這個值時, 開啟一個任務對小文件進行合并
5. 什么是嚴格模式?
嚴格模式下, hive會阻止用戶進行三種類型的sql與
- 對分區(qū)表的查詢, wher條件中沒有指定分區(qū)列的值
- 產(chǎn)生笛卡爾積的join操作
- 使用了order by 卻沒有使用limit
6. 談談hive的優(yōu)化
- 1. mapper個數(shù)和reducer個數(shù)的優(yōu)化
-
2. 對于count(distinct) 語法的優(yōu)化
使用count() group by進行優(yōu)化因為這個語法在mapper端group by后, 會開啟mapper端聚合減少reduce端的輸入量; 而count(distinct) 計算全都壓倒reduer, 把key分散到reducer后還要在每個reducer上對key進行排序去重 -
3. 對于order by 語法的優(yōu)化
order by是全局排序, 只會生成1個reducer來處理所有mapper的輸出. 但是往往我們并不需要在某個字段上完全的全局有序, 而是希望局部上有序, 所以可是使用其他字段先進行distribute by,再在原字段上sort by
select uid,upload_time,event_type,record_data f
from calendar_record_log
where day_p between '20190101' and '20190131'
order by upload_time desc,event_type desc;
-- 這個語句在數(shù)據(jù)量很大時無法計算, 可以做如下改寫
select uid,upload_time,event_type,record_data
from calendar_record_log
where day_p between '20190101' and '20190131'
distribute by uid
sort by upload_time desc,event_type desc;
-
4. 對于join語法的優(yōu)化
-
使用
map join
當使用join時, 如果發(fā)現(xiàn)其中某個表很小, 可以完全放進內(nèi)存的時候, 就可以將這張表指定成map join分發(fā)的表. 有2中方法指定- 手動指定:
select /*+MAPJOIN(b)*/ a.a1,a.a2,b.b2 from tablea a JOIN tableb b ON a.a1=b.b1緩存多張小表:
select /*+MAPJOIN(b,c)*/ a.a1,a.a2,b.b2 from tablea a JOIN tableb b ON a.a1=b.b1 JOIN tbalec c on a.a1=c.c1- 在Hive0.11后,Hive默認啟動該優(yōu)化
可以通過以下兩個屬性來設置該優(yōu)化的觸發(fā)時機-
hive.auto.convert.join: 默認值為true,自動開戶MAPJOIN優(yōu)化 -
hive.mapjoin.smalltable.filesize: 默認值為2500000(25M), 如果表的大小小于此值就會被加載進內(nèi)存中
-
此外, 使用使用MAPJOIN時,需要注意:
* LEFT OUTER JOIN的左表必須是大表;
* RIGHT OUTER JOIN的右表必須是大表; 調(diào)整map個數(shù)和reduce個數(shù)
-
7. 內(nèi)部表和外部表?
內(nèi)部表數(shù)據(jù)由Hive自身管理,外部表數(shù)據(jù)由HDFS管理;刪除內(nèi)部表會直接刪除元數(shù)據(jù)(metadata)及存儲數(shù)據(jù);刪除外部表僅僅會刪除元數(shù)據(jù),HDFS上的文件并不會被刪除。
8. 分區(qū)表和分桶表的區(qū)別
- 分區(qū)表: Hive 數(shù)據(jù)表可以根據(jù)某些字段進行分區(qū)操作,細化數(shù)據(jù)管理,讓部分查詢更快,不同分區(qū)對應不同的目錄;
- 分桶表:表和分區(qū)也可以進一步被劃分為桶,分桶是相對分區(qū)進行更細粒度的劃分。分桶將整個數(shù)據(jù)內(nèi)容按照某列屬性值的hash值進行區(qū)分,不同的桶對應不同的文件。