記錄一些Hive的優化點,和能夠提升的效率差異。

Hive是目前應用最多最廣的SQL on Hadoop工具,近期很多專業的大資料公司推出了很多新的,基於列式或者記憶體熱資料的SQL工具,像Impala,Tez,Spark等等,但是Hive仍然是目前使用率最高和普及面最廣的SQL on Hadoop的工具。在以前淘寶羅李的報告中,淘寶90%的業務跑在Hive上面。暴風影音的比例更高一些,大概95%以上都是跑在Hive上面。儘管很多人對Hive有看法,效率低,查詢慢,bug多。但是並不可否認hive是一個開創性的工具,提供了更多的想象空間。而且,在生產叢集上的資料查詢程式的開發效率,Hive要遠遠高於自己寫MR。

在預設情況下,Hive的配置引數比較保守,所以效率會比較差一點,修改配置會讓查詢效率有比較大的提升,記錄幾個對查詢效率影響比較重要的引數。

首先拿到一個hive要修改的就是他的後設資料儲存,預設情況下,Hive是用Derby記憶體資料庫儲存後設資料,不明白,都是嵌入式資料庫,Hive為啥不用SQLite呢,之前寫過修改後設資料儲存的文章,不在贅述。修改後設資料儲存的傳送門在這裡

Hive引數優化:

hive.map.aggr true 是否在 Map 端進行聚合,預設為 True
hive.groupby.mapaggr.checkinterval 100000 在 Map 端進行聚合操作的條目數目
hive.groupby.skewindata true 資料傾斜聚合優化,當選項設定為 true,生成的查詢計劃會有兩個 MR Job。第一個 MR Job 中,Map 的輸出結果集合會隨機分佈到 Reduce 中,每個 Reduce 做部分聚合操作,並輸出結果,這樣處理的結果是相同的 Group By Key 有可能被分發到不同的 Reduce 中,從而達到負載均衡的目的;第二個 MR Job 再根據預處理的資料結果按照 Group By Key 分佈到 Reduce 中(這個過程可以保證相同的 Group By Key 被分佈到同一個 Reduce 中),最後完成最終的聚合操作。
mapred.reduce.tasks -1 每任務最大使用reduce數
hive.exec.reducers.max 999 Hive最大使用reduce槽位數
javax.jdo.option.Multithreaded true jdbc訪問後設資料庫採用多執行緒併發
hive.optimize.groupby true 優化group by
hive.optimize.union.remove false 在大量union情況下進行優化 預設false,需要帶有partition的表才能用
hive.exec.parallel true 並行執行巢狀select,預設 false
hive.exec.parallel.thread.number 16 執行巢狀sql最大並行數

比較重要是頭幾個和後幾個,尤其是最後兩個,效能提升效果是最明顯的。但是會同時開啟更多的MR任務,這就需要一個平衡了。

巢狀SQL並行執行優化:

set hive.exec.parallel=true;

set hive.exec.parallel.thread.number=16;

效率可提升至少100%

某job需要11個stage:

非並行35分鐘

並行8個job執行10分鐘

並行16個job執行6分鐘

Hive查詢的優化:

一、資料量大的表和資料量小的表做關聯的時候,把資料量小的表放到join前面去select。

   原因是在 Join 操作的 Reduce 階段,位於 Join 操作符左邊的表的內容會被載入進記憶體,將條目少的表放在左邊,可以有效減少發生記憶體溢位錯誤的機率。

二、Join優化

   Join查詢操作中如果存在多個join,且所有參與join的表中其參與join的key都相同,則會將所有的join合併到一個mapred程式中。

   例:

   SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)  在一個mapre程式中執行join

   SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)   在兩個mapred程式中執行join

   Map join的關鍵在於join操作中的某個表的資料量很小

   例:

   SELECT /*+ MAPJOIN(b) */ a.key, a.value  FROM a join b on a.key = b.key

三、用sum() group by的方式來替換count(distinct)。

四、排序優化

   Order by 實現全域性排序,一個reduce實現,效率低

   Sort by 實現部分有序,單個reduce輸出的結果是有序的,效率高,通常和DISTRIBUTE BY關鍵字一起使用(DISTRIBUTE BY關鍵字 可以指定map 到 reduce端的分發key)

   CLUSTER BY col1 等價於DISTRIBUTE BY col1 SORT BY col1.

五、合併小檔案

   檔案數目過多,會給 HDFS 帶來壓力,並且會影響處理效率,可以通過合併 Map 和 Reduce 的結果檔案來儘量消除這樣的影響

   hive.merge.mapfiles = true是否和並 Map 輸出檔案,預設為 True

   hive.merge.mapredfiles = false是否合併 Reduce 輸出檔案,預設為 False

   hive.merge.size.per.task = 256*1000*1000合併檔案的大小。

   這裡的引數沒有寫到上面的表格裡是因為這是可以根據任務不同臨時設定的,而不一定非要是全域性設定。有時候全域性設定了反而對大檔案的操作有效能影響。

六、使用分割槽,RCFile,lzo,ORCFile等

   Hive中的每個分割槽都對應hdfs上的一個目錄,分割槽列也不是表中的一個實際的欄位,而是一個或者多個偽列,在表的資料檔案中實際上並不儲存分割槽列的資訊與資料。Partition關鍵字中排在前面的為主分割槽(只有一個),後面的為副分割槽

   靜態分割槽:靜態分割槽在載入資料和使用時都需要在sql語句中指定

   例:(stat_date=`20120625`,province=`hunan`)

   動態分割槽:使用動態分割槽需要設定hive.exec.dynamic.partition引數值為true,預設值為false,在預設情況下,hive會假設主分割槽時靜態分割槽,副分割槽使用動態分割槽;如果想都使用動態分割槽,需要設定set hive.exec.dynamic.partition.mode=nostrick,預設為strick

   例:(stat_date=`20120625`,province)

七、使用外部表而儘量少用內部表,這主要從資料的安全性上考量。