hive優化總結

開發優化:

1、分區、列剪裁。

       在查詢的過程中減少不必要的分區,只讀取查詢中所需要用到的列,而忽略其它列

2、謂詞下推。

       SQL語句中where謂詞邏輯提前執行,減少下游處理數據量

select a,b from table_a join
(select a,b from table_b where log_date='20200323') table_c
on table_a.a = table_c.a

        先從table中挑選出參與計算的數據,指定分區,指定列,減少後續處理數據量

3、兩表join,小表在前

        在 Reduce 階段,位於 Join 操作符左邊的表的內容會被加載進內存,載入條目較少的表 可以有效減少 OOM(out of memory)即內存溢出。所以對於同一個 key 來說,對應的 value 值小的放前,大的放後,這便是“小表放前”原則。 若一條語句中有多個 Join,依據 Join 的條件相同與否,有不同的處理方法。如果 Join 的 key 相同,不管有多少個表,都會則會合併爲一個 Map-Reduce

4、使用map join

      Join 操作在 Map 階段完成,不再需要Reduce,前提條件是需要的數據在 Map 的過程中可以訪問到

insert overwrite table r
select /* + MAPJOIN(a) */ b.a1,b.a2
from a join b on a.a1=b.a1

     map join的配置項是hive.auto.convert.join,默認值true,對應邏輯優化器是MapJoinProcessor。
還有一些參數用來控制map join的行爲,比如hive.mapjoin.smalltable.filesize,當build table大小小於該值就會啓用map join,默認值25000000(25MB)。還有hive.mapjoin.cache.numrows,表示緩存build table的多少行數據到內存,默認值25000。

5、group by 替代distinct

      當要統計某一列的去重數時,如果數據量很大,count(distinct)就會非常慢,原因與order by類似,count(distinct)邏輯只會有很少的reducer來處理。這時可以用group by來改寫

select count(1) from (
select uid from a
where log_date = 20200323
group by uid
) t;

 

配置調優

1、設置mapper個數

       可以直接通過參數mapred.map.tasks(默認值2)來設定mapper數的期望值,但它不一定會生效,下面會提到。

       設輸入文件的總大小爲total_input_size。HDFS中,一個塊的大小由參數dfs.block.size指定,默認值64MB或128MB。在默認情況下,mapper數就是:default_mapper_num = total_input_size / dfs.block.size

        參數mapred.min.split.size(默認值1B)和mapred.max.split.size(默認值64MB)分別用來指定split的最小和最大大小。split大小和split數計算規則是:
split_size = MAX(mapred.min.split.size, MIN(mapred.max.split.size, dfs.block.size))
split_num = total_input_size / split_size

         得出mapper數:mapper_num = MIN(split_num, MAX(default_num, mapred.map.tasks))

2、設置reducer個數

      reducer數量的確定方法比mapper簡單得多。使用參數mapred.reduce.tasks可以直接設定reducer數量,不像mapper一樣是期望值。但如果不設這個參數的話,Hive就會自行推測,邏輯如下:

       參數hive.exec.reducers.bytes.per.reducer用來設定每個reducer能夠處理的最大數據量,默認值1G(1.2版本之前)或256M(1.2版本之後)。

       參數hive.exec.reducers.max用來設定每個job的最大reducer數量,默認值999(1.2版本之前)或1009(1.2版本之後)。

       得出reducer數:reducer_num = MIN(total_input_size / reducers.bytes.per.reducer, reducers.max)

       reducer數量與輸出文件的數量相關。如果reducer數太多,會產生大量小文件,對HDFS造成壓力。如果reducer數太少,每個reducer要處理很多數據,容易拖慢運行時間或者造成OOM。

3、合併小文件

        輸入階段合併需要更改Hive的輸入文件格式,即參數hive.input.format,默認值是org.apache.hadoop.hive.ql.io.HiveInputFormat,我們改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
這樣比起上面調整mapper數時,又會多出兩個參數,分別是mapred.min.split.size.per.nodemapred.min.split.size.per.rack,含義是單節點和單機架上的最小split大小。如果發現有split大小小於這兩個值(默認都是100MB),則會進行合併。

         輸出階段合併直接將hive.merge.mapfileshive.merge.mapredfiles都設爲true即可,前者表示將map-only任務的輸出合併,後者表示將map-reduce任務的輸出合併。另外,hive.merge.size.per.task可以指定每個task輸出後合併文件大小的期望值,hive.merge.size.smallfiles.avgsize可以指定所有輸出文件大小的均值閾值,默認值都是1GB。如果平均大小不足的話,就會另外啓動一個任務來進行合併。

4、啓用壓縮

       壓縮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即可。

5、JVM重用

        在MR job中,默認是每執行一個task就啓動一個JVM。如果task非常小而碎,那麼JVM啓動和關閉的耗時就會很長。可以通過調節參數mapred.job.reuse.jvm.num.tasks來重用。例如將這個參數設成5,那麼就代表同一個MR job中順序執行的5個task可以重複使用一個JVM,減少啓動和關閉的開銷。但它對不同MR job中的task無效。

6、並行執行

        Hive中互相沒有依賴關係的job間是可以並行執行的,最典型的就是多個子查詢union all。在集羣資源相對充足的情況下,可以開啓並行執行,即將參數hive.exec.parallel設爲true。另外hive.exec.parallel.thread.number可以設定並行執行的線程數,默認爲8,一般都夠用。

6、嚴格模式

所謂嚴格模式,就是強制不允許用戶執行3種有風險的HiveSQL語句,一旦執行會直接失敗。這3種語句是:

  • 查詢分區表時不限定分區列的語句;

  • 兩表join產生了笛卡爾積的語句;

  • 用order by來排序但沒有指定limit的語句。

要開啓嚴格模式,需要將參數hive.mapred.mode設爲strict。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章