Hive 在工作中的調優總結

来源:https://www.cnblogs.com/fx67ll/archive/2023/02/13/hive-optimize-inwork.html
-Advertisement-
Play Games

總結了一下在以往工作中,對於`Hive SQL`調優的一些實際應用,是日常積累的一些優化技巧,如有出入,歡迎在評論區留言探討~ ...


總結了一下在以往工作中,對於Hive SQL調優的一些實際應用,是日常積累的一些優化技巧,如有出入,歡迎在評論區留言探討~

EXPLAIN 查看執行計劃

建表優化

分區

  1. 分區表基本操作,partitioned
  2. 二級分區
  3. 動態分區

分桶

  1. 分桶表基本操作,clustered
  2. 分桶表主要是抽樣查詢,找出具有代表性的結果

選擇合適的文件格式和壓縮格式

  1. LZO,拉茲羅
  2. Snappy
  3. 壓縮速度快,壓縮比高

HiveSQL語法優化

單表查詢優化

  1. 列裁剪和分區裁剪,全表和全列掃描效率都很差,生產環境絕對不要使用SELECT *,所謂列裁剪就是在查詢時只讀取需要的列,分區裁剪就是只讀取需要的分區

    • 與列裁剪優化相關的配置項是hive.optimize.cp,預設是true
    • 與分區裁剪優化相關的則是hive.optimize.pruner,預設是true
    • HiveSQL解析階段對應的則是ColumnPruner邏輯優化器
  2. Group By 配置調整,map階段會把同一個key發給一個reduce,當一個key過大時就傾斜了,可以開啟map端預聚合,可以有效減少shuffle數據量並

    # 是否在map端聚合,預設為true
    set hive.map.aggr = true;
    
    # 在map端聚合的條數
    set hive.groupby.mapaggr.checkintervel = 100000;
    
    # 在數據傾斜的時候進行均衡負載(預設是false),開啟後會有 兩個`mr任務`。
    # 當選項設定為true時,第一個 `mr任務` 會將map輸出的結果隨機分配到`reduce`,
    # 每個`reduce`會隨機分佈到`reduce`上,這樣的處理結果是會使相同的`group by key`分到不同的`reduce`上。
    # 第二個 `mr任務` 再根據預處理的結果按`group by key`分到`reduce`上,
    # 保證相同`group by key`的數據分到同一個`reduce`上。
    
    # *切記!!!* 
    # 這樣能解決數據傾斜,但是不能讓運行速度更快  
    # 在數據量小的時候,開始數據傾斜負載均衡可能反而會導致時間變長  
    # 配置項畢竟是死的,單純靠它有時不能根本上解決問題
    # 因此還是建議自行瞭解數據傾斜的細節,並優化查詢語句  
    set hive.groupby.skewindata = true;
    
  3. Vectorization,矢量計算技術,通過設置批處理的增量大小為1024行單次來達到比單行單次更好的效率

    # 開啟矢量計算  
    set hive.vectorized.execution.enabled = true;
    
    # 在reduce階段開始矢量計算  
    set hive.vectorized.execution.reduce.enabled = true;
    
  4. 多重模式,一次讀取多次插入,同一張表的插入操作優化成先from tableinsert

  5. in/exists或者join用left semi join代替(為什麼替代擴展一下~)

多表查詢優化

  1. CBO優化,成本優化器,代價最小的執行計劃就是最好的執行計劃

    • join的時候表的順序關係,前面的表都會被載入到記憶體中,後面的表進行磁碟掃描
    • 通過hive.cbo.enable,自動優化hivesql中多個join的執行順序
    • 可以通過查詢一下參數,這些一般都是true,無需修改
    set hive.cbo.enable = true;
    set hive.compute.query.using.stats = true;
    set hive.stats.fetch.column.stats = true;
    set hive.stats.fetch.partition.stats = true;
    
  2. 謂詞下推(非常關鍵的一個優化),將sql語句中的where謂詞邏輯都儘可能提前執行,減少下游處理的數據量,
    在關係型資料庫如MySQL中,也有謂詞下推(Predicate Pushdown,PPD)的概念,
    它就是將sql語句中的where謂詞邏輯都儘可能提前執行,減少下游處理的數據量

    # 這個設置是預設開啟的 
    # 如果關閉了但是cbo開啟,那麼關閉依然不會生效 
    # 因為cbo會自動使用更為高級的優化計劃  
    # 與它對應的邏輯優化器是PredicatePushDown
    # 該優化器就是將OperatorTree中的FilterOperator向上提
    set hive.optimize.pdd = true;
    
    # 舉個例子
    # 對forum_topic做過濾的where語句寫在子查詢內部,而不是外部
    select a.uid,a.event_type,b.topic_id,b.title
    from calendar_record_log a
    left outer join (
      select uid,topic_id,title from forum_topic
      where pt_date = 20220108 and length(content) >= 100
    ) b on a.uid = b.uid
    where a.pt_date = 20220108 and status = 0;
    
  3. Map Join,map join是指將join操作兩方中比較小的表直接分發到各個map進程的記憶體中,在map中進行join的操作。
    map join特別適合大小表join的情況,Hive會將build tableprobe tablemap端直接完成join過程,消滅了reduce,減少shuffle,所以會減少開銷

    • set hive.auto.convert.join = true,配置開啟,預設是true
    • 註意!!! 如果執行小表join大表,小表作為主連接的主表,所有數據都要寫出去,此時會走reduce階段,mapjoin會失效
    • 大表join小表不受影響,上一條的原因主要是因為小表join大表的時候,map階段不知道reduce的結果其他reduce是否有,
    • 所以必須在最後reduce聚合的時候再處理,就產生了reduce的開銷
    # 舉個例子
    # 在最常見的`hash join`方法中,一般總有一張相對小的表和一張相對大的表,
    # 小表叫`build table`,大表叫`probe table`  
    # Hive在解析帶join的SQL語句時,會預設將最後一個表作為`probe table`,
    # 將前面的表作為`build table`並試圖將它們讀進記憶體  
    # 如果表順序寫反,`probe table`在前面,引發`OOM(記憶體不足)`的風險就高了  
    # 在維度建模數據倉庫中,事實表就是`probe table`,維度表就是`build table`  
    # 假設現在要將日曆記錄事實表和記錄項編碼維度表來`join`  
    select a.event_type,a.event_code,a.event_desc,b.upload_time
    from calendar_event_code a
    inner join (
      select event_type,upload_time from calendar_record_log
      where pt_date = 20220108
    ) b on a.event_type = b.event_type;
    
  4. Map Join,大表和大表的MapReduce任務,可以使用SMB Join

    • 直接join耗時會很長,但是根據某欄位分桶後,兩個大表每一個桶就是一個小文件,兩個表的每個小文件的分桶欄位都應該能夠一一對應(hash值取模的結果)
    • 總結就是分而治之,註意兩個大表的分桶欄位和數量都應該保持一致
    set hive.optimize.bucketmapjoin = true;
    set hive.optimeize.bucketmapjoin.sortedmerge = true;
    hive.input.format = org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
    
  5. 多表join時key相同,這種情況會將多個join合併為一個mr 任務來處理

    # 舉個例子
    # 如果下麵兩個join的條件不相同  
    # 比如改成a.event_code = c.event_code  
    # 就會拆成兩個MR job計算
    select a.event_type,a.event_code,a.event_desc,b.upload_time
    from calendar_event_code a
    inner join (
      select event_type,upload_time from calendar_record_log
      where pt_date = 20220108
    ) b on a.event_type = b.event_type
    inner join (
      select event_type,upload_time from calendar_record_log_2
      where pt_date = 20220108
    ) c on a.event_type = c.event_type;
    
  6. 笛卡爾積,在生產環境中嚴禁使用

其他查詢優化

  1. Sort By 代替 Order By,HiveQL中的order by與其他sql方言中的功能一樣,就是將結果按某欄位全局排序,這會導致所有map端數據都進入一個reducer中,
    在數據量大時可能會長時間計算不完。如果使用sort by,那麼還是會視情況啟動多個reducer進行排序,並且保證每個reducer內局部有序。
    為了控制map端數據分配到reducerkey,往往還要配合distribute by一同使用,如果不加distribute by的話,map端數據就會隨機分配到reducer

    # 舉個例子
    select uid,upload_time,event_type,record_data
    from calendar_record_log
    where pt_date >= 20220108 and pt_date <= 20220131
    distribute by uid
    sort by upload_time desc,event_type desc;
    
  2. Group By代替Distinct,當要統計某一列的去重數時,如果數據量很大,count(distinct)就會非常慢,原因與order by類似,
    count(distinct)邏輯只會有很少的reducer來處理。但是這樣寫會啟動兩個mr任務(單純distinct只會啟動一個),
    所以要確保數據量大到啟動mr任務overhead遠小於計算耗時,才考慮這種方法,當數據集很小或者key的傾斜比較明顯時,group by還可能會比distinct

數據傾斜

註意要和數據過量的情況區分開,數據傾斜是大部分任務都已經執行完畢,但是某一個任務或者少數幾個任務,一直未能完成,甚至執行失敗,
而數據過量,是大部分任務都執行的很慢,這種情況需要通過擴充執行資源的方式來加快速度,大數據編程不怕數據量大,就怕數據傾斜,一旦數據傾斜,嚴重影響效率

單表攜帶了 Group By 欄位的查詢

  1. 任務中存在group by操作,同時聚合函數為countsum,單個key導致的數據傾斜可以這樣通過設置開啟map端預聚合參數的方式來處理
    # 是否在map端聚合,預設為true
    set hive.map.aggr = true;
    
    # 在map端聚合的條數
    set hive.groupby.mapaggr.checkintervel = 100000;
    
    # 有數據傾斜的時候開啟負載均衡,這樣會生成兩個mr任務
    set hive.groupby.skewindata = true;
    
  2. 任務中存在group by操作,同時聚合函數為countsum,多個key導致的數據傾斜可以通過增加reduce的數量來處理
    • 增加分區可以減少不同分區之間的數據量差距,而且增加的分區時候不能是之前分區數量的倍數,不然會導致取模結果相同繼續分在相同分區
    • 第一種修改方式
    # 每個reduce處理的數量
    set hive.exec.reduce.bytes.per.reducer = 256000000;
    
    # 每個任務最大的reduce數量
    set hive.exec.reducers.max = 1009;
    
    # 計算reducer數的公式,根據任務的需要調整每個任務最大的reduce數量  
    N = min(設置的最大數,總數量數/每個reduce處理的數量)
    
    • 第二種修改方式
    # 在hadoop的mapred-default.xml文件中修改
    set mapreduce.job.reduces = 15;
    

兩表或多表的 join 關聯時,其中一個表較小,但是 key 集中

  1. 設置參數增加map數量
    # join的key對應記錄條數超過該數量,會進行分拆  
    set hive.skewjoin.key = 1000;
    
    # 並設置該參數為true,預設是false
    set hive.optimize.skewjoin = true;
    
    # 上面的參數如果開啟了會將計算數量超過閾值的key寫進臨時文件,再啟動另外一個任務做map join  
    # 可以通過設置這個參數,控制第二個任務的mapper數量,預設10000
    set hive.skewjoin.mapjoin.map.tasks = 10000;
    
  2. 使用mapjoin,減少reduce從根本上解決數據傾斜,參考HiveSQL語法優化 -> 多表查詢優化 -> Map Join,大表和大表的MapReduce任務,SMB Join

兩表或多表的 join 關聯時,有 Null值 或 無意義值

這種情況很常見,比如當事實表是日誌類數據時,往往會有一些項沒有記錄到,我們視情況會將它置為null,或者空字元串-1等,
如果缺失的項很多,在做join時這些空值就會非常集中,拖累進度,因此,若不需要空值數據,就提前寫where語句過濾掉,
需要保留的話,將空值key用隨機方式打散,例如將用戶ID為null的記錄隨機改為負值

select a.uid,a.event_type,b.nickname,b.age
from (
  select 
  (case when uid is null then cast(rand()*-10240 as int) else uid end) as uid,
  event_type from calendar_record_log
  where pt_date >= 20220108
) a left outer join (
  select uid,nickname,age from user_info where status = 4
) b on a.uid = b.uid;

兩表或多表的 join 關聯時,數據類型不統一

比如int類型和string類型進行關聯,關聯時候以小類型作為分區,這裡intstring會到一個reduceTask中,如果數據量多,會造成數據傾斜

# 可以通過轉換為同一的類型來處理
cast(user.id as string)

單獨處理傾斜key

這其實是上面處理空值方法的拓展,不過傾斜的key變成了有意義的,一般來講傾斜的key都很少,我們可以將它們抽樣出來,
對應的行單獨存入臨時表中,然後打上一個較小的隨機數首碼(比如0~9),最後再進行聚合

Hive Job 優化

Hive Map 優化

Map數量多少的影響

  1. Map數過大
    • map階段輸出文件太小,產生大量小文件
    • 初始化和創建map的開銷很大
  2. Map數太小
    • 文件處理或查詢併發度小,Job執行時間過長
    • 大量作業時,容易堵塞集群

控制Map數的原則

根據實際情況,控制map數量需要遵循兩個原則

  1. 第一是使大數據量利用合適的map
  2. 第二是使單個map任務處理合適的數據量

複雜文件適當增加Map數

  1. input的文件都很大,任務邏輯複雜,map執行非常慢的時候,可以考慮增加map數,來使得每個map處理的數據量減少,從而提高任務的執行效率
  2. 那麼如何增加map的數量呢?在map階段,文件先被切分成split塊,而後每一個split切片對應一個Mapper任務
    FileInputFormat這個類先對輸入文件進行邏輯上的劃分,以128m為單位,將原始數據從邏輯上分割成若幹個split,每個split切片對應一個mapper任務
    所以說減少切片的大小就可增加map數量
  3. 可以依據公式計算computeSliteSize(Math.max(minSize, Math.min(maxSize, blockSize))) = blockSize = 128m
  4. 執行語句:set mapreduce.input.fileinputformat.split.maxsize = 100;

小文件進行合併減少Map數

為什麼要進行小文件合併?因為如果一個任務有很多小文件(遠遠小於塊大小128m),則每個小文件也會被當做一個塊,用一個map任務來完成,
而一個map任務啟動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費,同時可執行的map數是受限的
兩種方式合併小文件

  1. Map執行前合併小文件,減少map數量
    // 每個Map最大輸入大小(這個值決定了合併後文件的數量)
    set mapred.max.split.size = 256000000;
    
    // 一個節點上split的至少的大小(這個值決定了多個DataNode上的文件是否需要合併)
    set mapred.min.split.size.per.node = 100000000;
    
    // 一個交換機下split的至少的大小(這個值決定了多個交換機上的文件是否需要合併)
    set mapred.min.split.size.per.rack = 100000000;
    
    // 執行Map前進行小文件合併
    set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
    
  2. Map-Reduce任務執行結束時合併小文件,減少小文件輸出
    // 設置map端輸出進行合併,預設為true
    set hive.merge.mapfiles = true;
    
    // 設置reduce端輸出進行合併,預設為false
    set hive.merge.mapredfiles = true;
    
    // 設置合併文件的大小,預設是256
    set hive.merge.size.per.task = 256 * 1000 * 1000;
    
    // 當輸出文件的平均大小小於該值時,啟動一個獨立的`MapReduce任務`進行文件`merge`。
    set hive.merge.smallfiles.avgsize = 16000000;
    

Map端預聚合減少Map數量

  1. 相當於在map端執行combiner,執行命令:set hive.map.aggr = true;
  2. combiners是對map端的數據進行適當的聚合,其好處是減少了從map端到reduce端的數據傳輸量
  3. 其作用的本質,是將map計算的結果進行二次聚合,使Key-Value<List>List的數據量變小,從而達到減少數據量的目的

推測執行

  1. 在分散式集群環境下,因為程式Bug(包括Hadoop本身的bug),負載不均衡或者資源分佈不均等原因,會造成同一個作業的多個任務之間運行速度不一致,
    有些任務的運行速度可能明顯慢於其他任務(比如一個作業的某個任務進度只有50%,而其他所有任務已經運行完畢),則這些任務會拖慢作業的整體執行進度
  2. Hadoop採用了推測執行(Speculative Execution)機制,它根據一定的法則推測出拖後腿的任務,併為這樣的任務啟動一個備份任務,
    讓該任務與原始任務同時處理同一份數據,並最終選用最先成功運行完成任務的計算結果作為最終結果
  3. 執行命令:set mapred.reduce.tasks.speculative.execution = true; # 預設是true
  4. 當然,如果用戶對於運行時的偏差非常敏感的話,那麼可以將這些功能關閉掉,如果用戶因為輸入數據量很大而需要執行長時間的map task或者reduce task的話,
    那麼啟動推測執行造成的浪費是非常巨大的

合理控制Map數量的實際案例

假設一個SQL任務:

SELECT COUNT(1) 
FROM fx67ll_alarm_count_copy
WHERE alarm_date = "2021-01-08";

該任務的輸入目錄inputdir是:/group/fx67ll_data/fx67ll_data_etl/date/fx67ll_alarm_count_copy/alarm_date=2021-01-08,共有194個文件,
其中很多是遠遠小於128m的小文件,總大小約9G,正常執行會用194個Map任務map總共消耗的計算資源:SLOTS_MILLIS_MAPS= 610,023
通過在Map執行前合併小文件,減少Map數

# 前面三個參數確定合併文件塊的大小
# 大於文件塊大小128m的,按照128m來分隔 
# 小於128m,大於100m的,按照100m來分隔
# 把那些小於100m的(包括小文件和分隔大文件剩下的),進行合併,最終生成了74個塊
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

合併後,用了74個map任務,map消耗的計算資源:SLOTS_MILLIS_MAPS= 323,098,對於這個簡單SQL任務,執行時間上可能差不多,但節省了一半的計算資源

再假設這樣一個SQL任務:

SELECT data_fx67ll,
COUNT(1),
COUNT(DISTINCT id),
SUM(CASE WHEN …),
SUM(CASE WHEN …),
SUM(…)
FROM fx67ll_device_info_zs
GROUP data_fx67ll

如果表fx67ll_device_info_zs只有一個文件,大小為120m,但包含幾千萬的記錄,如果用1個map去完成這個任務,肯定是比較耗時的,
這種情況下,我們要考慮將這一個文件合理的拆分成多個
增加Reduce數量,來增加Map數量

set mapred.reduce.tasks=10;
CREATE TABLE fx67ll_device_info_zs_temp
AS
SELECT * 
FROM fx67ll_device_info_zs
DISTRIBUTE BY RAND(123);

這樣會將fx67ll_device_info_zs表的記錄,隨機的分散到包含10個文件的fx67ll_device_info_zs_temp表中,
再用fx67ll_device_info_zs_temp代替上面sql中的fx67ll_device_info_zs表,
則會用10個map任務去完成,每個map任務處理大於12m(幾百萬記錄)的數據,效率肯定會好很多

Hive Reduce 優化

Reduce數量多少的影響

  1. map一樣,啟動和初始化reduce也會消耗時間和資源
  2. 另外,有多少個reduce,就會有多少個輸出文件,如果生成了很多個小文件,那麼如果這些小文件作為下一個任務的輸入,則也會出現小文件過多的問題

控制Reduce數的原則

map一樣,控制reduce數量需要遵循兩個原則

  1. 第一是使大數據量利用合適的reduce
  2. 第二是使單個reduce任務處理合適的數據量

Hive自己如何確定Reduce數

reduce個數的設定極大影響任務執行效率,不指定reduce個數的情況下,Hive會猜測確定一個reduce個數,基於以下兩個設定:

# 每個reduce任務處理的數據量,預設為 1000^3=1G
hive.exec.reducers.bytes.per.reducer

# 每個任務最大的reduce數,預設為999
hive.exec.reducers.max

計算reducer數的公式很簡單N = min(參數2,總輸入數據量 / 參數1)
即,如果reduce的輸入(map的輸出)總大小不超過1G,那麼只會有一個reduce任務

舉個例子:

SELECT alarm_date,
		COUNT(1) 
FROM fx67ll_alarm_count_copy
WHERE alarm_date = "2021-01-08"
GROUP BY alarm_date;

該任務的輸入目錄inputdir是:/group/fx67ll_data/fx67ll_data_etl/date/fx67ll_alarm_count_copy/alarm_date=2021-01-08
總大小為9G多,因此這句有10個reduce

如何調整Reduce數量

註意!!!實際開發中,reduce的個數一般通過程式自動推定,而不人為干涉,因為人為控制的話,如果使用不當很容易造成結果不准確,且降低執行效率

  1. 通過調整每個reduce任務處理的數據量來調整reduce個數,處理的數據量少了,任務數就多了
    # 設置每個reduce任務處理的數據量500M,預設是1G
    set hive.exec.reducers.bytes.per.reducer = 500000000;
    
    SELECT alarm_date,
    		COUNT(1) 
    FROM fx67ll_alarm_count_copy
    WHERE alarm_date = "2021-01-08"
    GROUP BY alarm_date;
    
    這次有20個reduce
    
  2. 直接調整每個Job中的最大reduce數量,過於簡單粗暴,慎用,儘量不要,雖然設置了reduce的個數看起來好像執行速度變快了,但是實際並不是這樣的
    # 設置每個任務最大的reduce數為15個,預設為999
    set mapred.reduce.tasks = 15;
    
    SELECT alarm_date,
    		COUNT(1) 
    FROM fx67ll_alarm_count_copy
    WHERE alarm_date = "2021-01-08"
    GROUP BY alarm_date;
    
    這次有15個reduce
    

推測執行

參考map優化的最後一項

什麼情況下只有一個Reduce

很多時候你會發現任務中不管數據量多大,不管你有沒有設置調整reduce個數的參數,任務中一直都只有一個reduce任務,
其實只有一個reduce任務的情況,除了數據量小於hive.exec.reducers.bytes.per.reducer參數值的情況外,還有以下原因:

  1. 沒有Group By的彙總,例如:
    SELECT alarm_date,
    		COUNT(1) 
    FROM fx67ll_alarm_count_copy
    WHERE alarm_date = "2021-01-08"
    GROUP BY alarm_date;
    
    寫成
    
    SELECT COUNT(1) 
    FROM fx67ll_alarm_count_copy
    WHERE alarm_date = "2021-01-08";
    
    註意避免這樣情況的發生
    
  2. 用了Order by排序,因為它會對數據進行全局排序,所以數據量特別大的時候效率非常低,儘量避免
  3. 有笛卡爾積,生產環境必須嚴格避免

Hive 任務整體優化

Fetch抓取

Fetch抓取是指Hive在某些情況的查詢可以不必使用mr 任務,例如在執行一個簡單的select * from XX時,我們只需要簡單的進行抓取對應目錄下的數據即可。
hive-default.xml.template中,hive.fetch.task.conversion(預設是morn),老版本中預設是minimal
該屬性為morn時,在全局查找,欄位查找,limit查找等都不走mr 任務

本地模式

Hive也可以不將任務提交到集群進行運算,而是直接在一臺節點上處理,因為消除了提交到集群的overhead,所以比較適合數據量很小,且邏輯不複雜的任務。
設置hive.exec.mode.local.auto為true可以開啟本地模式,但任務的輸入數據總量必須小於hive.exec.mode.local.auto.inputbytes.max(預設值128MB)
且mapper數必須小於hive.exec.mode.local.auto.tasks.max(預設值4)reducer數必須為0或1,才會真正用本地模式執行

並行執行

Hive中互相沒有依賴關係的job間是可以並行執行的,最典型的就是多個子查詢union all
在集群資源相對充足的情況下,可以開啟並行執行,即將參數hive.exec.parallel設為true,
另外hive.exec.parallel.thread.number可以設定並行執行的線程數,預設為8,一般都夠用。
註意!!!沒資源無法並行,且數據量小時開啟可能還沒不開啟快,所以建議數據量大時開啟

嚴格模式

要開啟嚴格模式,需要將參數hive.mapred.mode設為strict
所謂嚴格模式,就是強制不允許用戶執行3種有風險的sql語句,一旦執行會直接失敗,這3種語句是:

  1. 查詢分區表時不限定分區列的語句
  2. 兩表join產生了笛卡爾積的語句
  3. 用order by來排序但沒有指定limit的語句

JVM重用

  1. 主要用於處理小文件過多的時候
  2. mr 任務中,預設是每執行一個task就啟動一個JVM,如果task非常小而碎,那麼JVM啟動和關閉的耗時就會很長
  3. 可以通過調節參數mapred.job.reuse.jvm.num.tasks來重用
  4. 例如將這個參數設成5,那麼就代表同一個mr 任務中順序執行的5個task可以重覆使用一個JVM,減少啟動和關閉的開銷,但它對不同mr 任務中的task無效

啟用壓縮

壓縮job的中間結果數據和輸出數據,可以用少量CPU時間節省很多空間,壓縮方式一般選擇Snappy,效率最高。
要啟用中間壓縮,需要設定hive.exec.compress.intermediate為true,
同時指定壓縮方式hive.intermediate.compression.codecorg.apache.hadoop.io.compress.SnappyCodec
另外,參數hive.intermediate.compression.type可以選擇對塊(BLOCK)還是記錄(RECORD)壓縮,BLOCK的壓縮率比較高。
輸出壓縮的配置基本相同,打開hive.exec.compress.output即可

採用合適的存儲格式

  1. 在Hive SQL的create table語句中,可以使用stored as ...指定表的存儲格式。
    Hive表支持的存儲格式有TextFileSequenceFileRCFileAvroORCParquet等。
    存儲格式一般需要根據業務進行選擇,在我們的實操中,絕大多數表都採用TextFileParquet兩種存儲格式之一。
  2. TextFile是最簡單的存儲格式,它是純文本記錄,也是Hive的預設格式,雖然它的磁碟開銷比較大,查詢效率也低,但它更多地是作為跳板來使用。
  3. RCFileORCParquet等格式的表都不能由文件直接導入數據,必須由TextFile來做中轉。
  4. ParquetORC都是Apache旗下的開源列式存儲格式。列式存儲比起傳統的行式存儲更適合批量OLAP查詢,並且也支持更好的壓縮和編碼。
  5. 我們選擇Parquet的原因主要是它支持Impala查詢引擎,並且我們對updatedelete事務性操作需求很低。

Hive的小文件

什麼情況下會產生小文件?

  1. 動態分區插入數據,產生大量的小文件,從而導致map數量劇增
  2. reduce數量越多,小文件也越多,有多少個reduce,就會有多少個輸出文件,如果生成了很多小文件,那這些小文件作為下一次任務的輸入
  3. 數據源本身就包含大量的小文件

小文件有什麼樣的危害?

  1. 從Hive的角度看,小文件會開很多map,一個map開一個java虛擬機jvm去執行,所以這些任務的初始化,啟動,執行會浪費大量的資源,嚴重影響性能
  2. 在hdfs中,每個小文件對象約占150byte,如果小文件過多會占用大量記憶體,這樣NameNode記憶體容量嚴重製約了集群的擴展
    • 每個hdfs上的文件,會消耗128位元組記錄其meta信息,所以大量小文件會占用大量記憶體

如何避免小文件帶來的危害?

從小文件產生的途經就可以從源頭上控制小文件數量

  1. 使用Sequencefile作為表存儲格式,不要用textfile,在一定程度上可以減少小文件
  2. 減少reduce的數量(可以使用參數進行控制)
  3. 少用動態分區,用時記得按distribute by分區

對於已有的小文件

  1. 使用hadoop archive命令把小文件進行歸檔,採用archive命令不會減少文件存儲大小,只會壓縮NameNode的空間使用
  2. 重建表,建表時減少reduce數量

我是 fx67ll.com,如果您發現本文有什麼錯誤,歡迎在評論區討論指正,感謝您的閱讀!
如果您喜歡這篇文章,歡迎訪問我的 本文github倉庫地址,為我點一顆Star,Thanks~

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文內容 這篇文章是實戰性質的,也就是說原理部分較少,屬於經驗總結,rust對於模塊的例子太少了。rust特性比較多(悲),本文的內容可能只是一部分,實現方式也不一定是這一種。 關於 rust 模塊的相關內容,準確來說:怎麼在源碼中引用其他模塊的內容。 關於 mod、 use 、as 這幾個關鍵字( ...
  • 效果圖 好久沒有寫wpf了。 最近看到飛書的點贊動畫非常有意思,決定試試,雖然不及飛書那樣的絢麗,但是練手還是可以的,希望自己的手藝還在! 那麼如何寫一個這樣的動畫呢? 首先需要刨析這個動畫的構成: 外圈圓 大拇指-1豎著 大拇指-2握著 顫動動畫 中心旋轉動畫 展開中心旋轉動畫 當我們分析這些東西 ...
  • 工作邏輯是用戶啟動主程式,主程式啟動更新程式,更新程式立刻檢查是否有已經下載好的更新包,如果有則立刻關閉主程式進行更新,如果沒有則訪問伺服器查詢更新包,併在後臺靜默下載,下載完成後等下一次主程式啟動時更新 由於只是簡單的更新程式,所以沒有用資料庫,客戶端版本號以一個json文件保存,服務端則直接以壓 ...
  • 1前言 爬蟲一般都是用Python來寫,生態豐富,動態語言開發速度快,調試也很方便 但是 我要說但是,動態語言也有其局限性,筆者作為老爬蟲帶師,幾乎各種語言都搞過,現在這個任務並不複雜,用我最喜歡的C#做小菜一碟~ 2開始 之前做 OneCat 項目的時候,最開始的數據採集模塊,就是用 C# 做的, ...
  • 修改Windows遠程桌面3389埠 Windows版本:windows10、Windows server 2016、2019(其他版本沒有測過,應該也適用) 1、Windows桌面上,點擊“開始-運行”或鍵盤按下“WIN+R”打開運行視窗,輸入“regedit”,點擊確定打開註冊表編輯器。 2、 ...
  • 自己編譯的內核進行修改後為後續方便查詢是那個版本的系統。 所以每次更改內核後都需要修改一下版本信息, 又因為內核一般是不變的為了區分所以增加到擴展版本上。 操作環境: 硬體是全志 V3S Linux內核是3.4 修改的方法: 方法一: 一個在menuconfig中進行增加 打開menuconfig ...
  • 1、大多數情況下很正常,偶爾很慢,則有如下原因 (1)、資料庫在刷新臟頁,例如 redo log 寫滿了需要同步到磁碟。 (2)、執行的時候,遇到鎖,如表鎖、行鎖。 (3)、sql寫的爛 2、這條 SQL 語句一直執行的很慢,則有如下原因 (1)、沒有用上索引或索引失效:例如該欄位沒有索引;或則由於 ...
  • 摘要:提供一種執行高效的TereData的marco遷移方案。 本文分享自華為雲社區《GaussDB(DWS)遷移 - teredata相容 -- macro相容 # 【玩轉PB級數倉GaussDB(DWS)】》,作者: 譡里個檔 。 Teradata的巨集是一組可以接受參數的SQL語句,通過調用巨集名 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...