Hive面試題

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ù)。
  • 如何處理
    1. key上加上隨機數(shù)打散, 然后最后計算結果時恢復成原來的key
    2. 過濾空值, 或者將空值變成一個字符串并加上隨機前綴, 由于隨機的key找不到相同的而執(zhí)行失敗
    3. 傾斜的key拿出來單獨處理, 最后和其它結果union all在一起(不去重不排序)
    4. 開啟參數(shù)hive.groupby.skewindata=true
      這會生成2個任務:
      1. 第一個任務: map的輸出結果隨機的分配到reduce上, 每個reduce按照key做第一次聚合
      2. 第二個任務: 將相同的key分布到同一個partition上, 再做第二次聚合
    5. 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ù)計算公式為:
mapper\_num = MIN(split\_num, MAX(default\_mapper\_num, mapred.map.tasks))
由于 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)小文件
    1. 動態(tài)分區(qū)插入數(shù)據(jù),產(chǎn)生大量的小文件,從而導致map數(shù)量劇增。
    2. reducer數(shù)量太多
    3. 數(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)化
    1. 使用map join
      當使用join時, 如果發(fā)現(xiàn)其中某個表很小, 可以完全放進內(nèi)存的時候, 就可以將這張表指定成map join分發(fā)的表. 有2中方法指定

      1. 手動指定:
      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
      
      1. 在Hive0.11后,Hive默認啟動該優(yōu)化
        可以通過以下兩個屬性來設置該優(yōu)化的觸發(fā)時機
        1. hive.auto.convert.join: 默認值為true,自動開戶MAPJOIN優(yōu)化
        2. hive.mapjoin.smalltable.filesize: 默認值為2500000(25M), 如果表的大小小于此值就會被加載進內(nèi)存中

      此外, 使用使用MAPJOIN時,需要注意:
      * LEFT OUTER JOIN的左表必須是大表;
      * RIGHT OUTER JOIN的右表必須是大表;

    2. 調(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ū)分,不同的桶對應不同的文件。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容