數據分析利器之hive優化十大原則
hive之於數據民工,就如同鋤頭之於農民伯伯。hive用的好,才能從地里(資料庫)里挖出更多的數據來。
用過hive的朋友,我想或多或少都有類似的經歷:一天下來,沒跑幾次hive,就到下班時間了。
hive在極大數據或者數據不平衡等情況下,表現往往一般,因此也出現了presto、spark-sql等替代品。今天不談其它,就來說說關於hive,個人的一點心得。
一. 表連接優化
1. 將大表放後頭
Hive假定查詢中最後的一個表是大表。它會將其它表緩存起來,然後掃描最後那個表。
因此通常需要將小表放前面,或者標記哪張表是大表:/*streamtable(table_name) */
2. 使用相同的連接鍵
當對3個或者更多個表進行join連接時,如果每個on子句都使用相同的連接鍵的話,那麼只會產生一個MapReduce job。
3. 盡量儘早地過濾數據
減少每個階段的數據量,對於分區表要加分區,同時只選擇需要使用到的欄位。
4. 盡量原子化操作
盡量避免一個SQL包含複雜邏輯,可以使用中間表來完成複雜的邏輯
二. 用insert into替換union all
如果union all的部分個數大於2,或者每個union部分數據量大,應該拆成多個insert into 語句,實際測試過程中,執行時間能提升50%
如:
insert overwite table tablename partition (dt= ....)
select ..... from ( select ... from A
union all
select ... from B union all select ... from C ) R
where ...;
可以改寫為:
insert into table tablename partition (dt= ....) select .... from A WHERE ...; insert into table tablename partition (dt= ....) select .... from B WHERE ...; insert into table tablename partition (dt= ....) select .... from C WHERE ...;
三. order by & sort by
order by : 對查詢結果進行全局排序,消耗時間長。需要 set hive.mapred.mode=nostrict
sort by : 局部排序,並非全局有序,提高效率。
四. transform+python
一種嵌入在hive取數流程中的自定義函數,通過transform語句可以把在hive中不方便實現的功能在python中實現,然後寫入hive表中。
語法:
select transform({column names1})
using "**.py"
as {column names2}
from {table name}
如果除python腳本外還有其它依賴資源,可以使用ADD ARVHIVE
五. limit 語句快速出結果
一般情況下,Limit語句還是需要執行整個查詢語句,然後再返回部分結果。
有一個配置屬性可以開啟,避免這種情況---對數據源進行抽樣
hive.limit.optimize.enable=true --- 開啟對數據源進行採樣的功能
hive.limit.row.max.size --- 設置最小的採樣容量
hive.limit.optimize.limit.file --- 設置最大的採樣樣本數
缺點:有可能部分數據永遠不會被處理到
六. 本地模式
對於小數據集,為查詢觸發執行任務消耗的時間>實際執行job的時間,因此可以通過本地模式,在單台機器上(或某些時候在單個進程上)處理所有的任務。
set oldjobtracker=${hiveconf:mapred.job.tracker};
set mapred.job.tracker=local;
set marped.tmp.dir=/home/edward/tmp; sql 語句 set mapred.job.tracker=${oldjobtracker};
-- 可以通過設置屬性hive.exec.mode.local.auto的值為true,來讓hve在適當的時候自動啟動這個優化,也可以將這個配置寫在$HOME/.hiverc文件中。
-- 當一個job滿足如下條件才能真正使用本地模式:
1.job的輸入數據大小必須小於參數:hive.exec.mode.local.auto.inputbytes.max(默認128MB)
2.job的map數必須小於參數:hive.exec.mode.local.auto.tasks.max(默認4)
3.job的reduce數必須為0或者1
可用參數hive.mapred.local.mem(默認0)控制child jvm使用的最大內存數。
七. 並行執行
hive會將一個查詢轉化為一個或多個階段,包括:MapReduce階段、抽樣階段、合併階段、limit階段等。默認情況下,一次只執行一個階段。 不過,如果某些階段不是互相依賴,是可以並行執行的。
set hive.exec.parallel=true,可以開啟並發執行。
set hive.exec.parallel.thread.number=16; //同一個sql允許最大並行度,默認為8。
會比較耗系統資源。
八. 調整mapper和reducer的個數
1 Map階段優化
map個數的主要的決定因素有: input的文件總個數,input的文件大小,集群設置的文件塊大小(默認128M,不可自定義)。
舉例:
a) 假設input目錄下有1個文件a,大小為780M,那麼hadoop會將該文件a分隔成7個塊(6個128m的塊和1個12m的塊),從而產生7個map數
b) 假設input目錄下有3個文件a,b,c,大小分別為10m,20m,130m,那麼hadoop會分隔成4個塊(10m,20m,128m,2m),從而產生4個map數
即,如果文件大於塊大小(128m),那麼會拆分,如果小於塊大小,則把該文件當成一個塊。
map執行時間:map任務啟動和初始化的時間+邏輯處理的時間。
1)減少map數
若有大量小文件(小於128M),會產生多個map,處理方法是:
set mapred.max.split.size=100000000; set mapred.min.split.size.per.node=100000000; set mapred.min.split.size.per.rack=100000000;
-- 前面三個參數確定合併文件塊的大小,大於文件塊大小128m的,按照128m來分隔,小於128m,大於100m的,按照100m來分隔,把那些小於100m的(包括小文件和分隔大文件剩下的)進行合併
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- 執行前進行小文件合併 2)增加map數
當input的文件都很大,任務邏輯複雜,map執行非常慢的時候,可以考慮增加Map數,來使得每個map處理的數據量減少,從而提高任務的執行效率。
set mapred.reduce.tasks=?
2 Reduce階段優化
調整方式:
-- set mapred.reduce.tasks=?
-- set hive.exec.reducers.bytes.per.reducer = ?
一般根據輸入文件的總大小,用它的estimation函數來自動計算reduce的個數:reduce個數 = InputFileSize / bytes per reducer
九.嚴格模式
set hive.marped.mode=strict ------ 防止用戶執行那些可能意想不到的不好的影響的查詢
-- 分區表,必須選定分區範圍
-- 對於使用order by的查詢,要求必須使用limit語句。因為order by為了執行排序過程會將所有的結果數據分發到同一個reducer中進行處理。
-- 限制笛卡爾積查詢:兩張表join時必須有on語句
十.數據傾斜
表現:任務進度長時間維持在99%(或100%),查看任務監控頁面,發現只有少量(1個或幾個)reduce子任務未完成。因為其處理的數據量和其他reduce差異過大。
單一reduce的記錄數與平均記錄數差異過大,通常可能達到3倍甚至更多。 最長時長遠大於平均時長。
原因
1)、key分布不均勻
2)、業務數據本身的特性
3)、建表時考慮不周
4)、某些SQL語句本身就有數據傾斜
關鍵詞情形後果join其中一個表較小,但是key集中分發到某一個或幾個Reduce上的數據遠高於平均值join大表與大表,但是分桶的判斷欄位0值或空值過多這些空值都由一個reduce處理,灰常慢group bygroup by 維度過小,某值的數量過多處理某值的reduce灰常耗時count distinct某特殊值過多處理此特殊值reduce耗時解決方案:
參數調節
hive.map.aggr=true
參考文獻:
1. 《hive編程指南》Edward Capriolo
對數據感興趣的小夥伴,歡迎交流,微信公共號:一白侃數
推薦閱讀:
※大數據那些事(28):卡夫卡們的故事
※技術分享丨HDFS 入門
※大數據那些事(12):Michael,Daniel和輪子
※Spark 2017 歐洲技術峰會摘要(人工智慧)
※穩定和性能如何兼顧?58大數據平台的技術演進與實踐