Hive(十二)【調優】
目錄
1.Fetch抓取
Fetch抓取:Hive中對某些情況的查詢可以不必使用MapReduce計算。
例如:SELECT * FROM emp;在這種情況下,Hive可以簡單地讀取emp對應的儲存目錄下的檔案,然後輸出查詢結果到控制檯。
在%HIVE_HOME%/conf/hive-default.xml.template檔案中hive.fetch.task.conversion預設是more,老版本hive預設是minimal,該屬性修改為more以後,在全域性查詢、欄位查詢、limit查詢等都不走mapreduce。
<property> <name>hive.fetch.task.conversion</name> <value>more</value> <description> Expects one of [none, minimal, more]. Some select queries can be converted to single FETCH task minimizing latency. Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incurs RS), lateral views and joins. 0. none : disable hive.fetch.task.conversion 1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only 2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns) </description> </property>
案例實操
(1)把hive.fetch.task.conversion設定成none,然後執行查詢語句,都會執行mapreduce程式
hive (default)> set hive.fetch.task.conversion=none;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;
(2)把hive.fetch.task.conversion設定成more,然後執行查詢語句,如下查詢方式都不會執行mapreduce程式
hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;
2.本地模式
本地模式:對於小資料集,Hive可以通過本地模式在單臺機器上處理所有的任務;
大多數的Hadoop Job是需要Hadoop提供的完整的可擴充套件性來處理大資料集的。不過,有時Hive的輸入資料量是非常小的。在這種情況下,為查詢觸發執行任務消耗的時間可能會比實際job的執行時間要多的多。對於大多數這種情況,Hive可以通過本地模式在單臺機器上處理所有的任務。對於小資料集,執行時間可以明顯被縮短。
使用者可以通過設定hive.exec.mode.local.auto的值為true,來讓Hive在適當的時候自動啟動這個優化。
set hive.exec.mode.local.auto=true; //開啟本地mr
//設定local mr的最大輸入資料量,當輸入資料量小於這個值時採用local mr的方式,預設為134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//設定local mr的最大輸入檔案個數,當輸入檔案個數小於這個值時採用local mr的方式,預設為4
set hive.exec.mode.local.auto.input.files.max=10;
案例實操
(1)開啟本地模式,並執行查詢語句
hive (default)> set hive.exec.mode.local.auto=true;
hive (default)> select * from emp cluster by deptno;
Time taken: 1.328 seconds, Fetched: 14 row(s)
(2)關閉本地模式,並執行查詢語句
hive (default)> set hive.exec.mode.local.auto=false;
hive (default)> select * from emp cluster by deptno;
Time taken: 20.09 seconds, Fetched: 14 row(s)
3.表的優化
3.1大小表join
將key相對分散,並且資料量小的表放在join的左邊,這樣可以有效減少記憶體溢位錯誤發生的機率;再進一步,可以使用map join讓小的維度表(1000條以下的記錄條數)先進記憶體。在map端完成reduce。
新版的hive已經對小表JOIN大表和大表JOIN小表進行了優化。小表放在左邊和右邊已經沒有明顯區別。
3.2大表Join大表
大表join大表可能出現數據傾斜的現象,因為某些key對應的資料太多,而相同key對應的資料都會發送到相同的reducer上,從而導致記憶體不夠,執行任務超時。
(1)空key過濾:將含空key欄位的資料過濾,在進行join操作
案例實操
調優前
insert overwrite table jointable select n.* from nullidtable n
left join bigtable o on n.id = o.id;
調優後
insert overwrite table jointable select n.* from nullidtable n
left join bigtable o on n.id = o.id;
(2)空key加隨機數轉換:給空key欄位通過nvl()賦值隨機數,讓這批資料隨機進入不同reducer;
案例實操
不隨機分佈空null值
(1)設定5個reduce個數
set mapreduce.job.reduces = 5;
(2)JOIN兩張表
insert overwrite table jointable
調優前
insert overwrite table jointable
select n.* from nullidtable n left join bigtable b on n.id = b.id;
調優後
insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on nvl(n.id,rand()) = o.id;
3.3map join
如果不指定MapJoin或者不符合MapJoin的條件,那麼Hive解析器會將Join操作轉換成Common Join,即:在Reduce階段完成join。容易發生資料傾斜。可以用MapJoin把小表全部載入到記憶體在map端進行join,避免reducer處理。
mapjoin工作機制
相關引數設定
(1)設定自動選擇Mapjoin
set hive.auto.convert.join = true; 預設為true
(2)大表小表的閾值設定(預設25M以下認為是小表):
set hive.mapjoin.smalltable.filesize=25000000;
案例實操
(1)開啟Mapjoin功能
set hive.auto.convert.join = true; 預設為true
(2)執行小表JOIN大表語句
insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from smalltable s
left join bigtable b
on s.id = b.id;
Time taken: 24.594 seconds
(3)執行大表JOIN小表語句
insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable b
left join smalltable s
on s.id = b.id;
Time taken: 24.315 seconds
3.4group By
預設情況下,Map階段同一Key資料分發給一個reduce,當一個key資料過大時就傾斜了。
開啟Map端聚合引數設定
(1)是否在Map端進行聚合,預設為True
set hive.map.aggr = true
(2)在Map端進行聚合操作的條目數目
set hive.groupby.mapaggr.checkinterval = 100000
(3)有資料傾斜的時候進行負載均衡(預設是false)
set 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中),最後完成最終的聚合操作
3.5 count(distinct)
資料量小的時候無所謂,資料量大的情況下,由於COUNT DISTINCT操作需要用一個Reduce Task來完成,這一個Reduce需要處理的資料量太大,就會導致整個Job很難完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換,但是需要注意group by造成的資料傾斜問題.
3.6笛卡爾積
避免笛卡爾積,join的時候不加on條件,或者無效的on條件,Hive只能使用1個reducer來完成笛卡爾積
3.7行列過濾
行處理:在分割槽剪裁中,當使用外關聯時,如果將副表的過濾條件寫在Where後面,那麼就會先全表關聯,之後再過濾,要先過濾後join
列處理:在SELECT中,只拿需要的列,如果有,儘量使用分割槽過濾,少用SELECT *。
3.8 分割槽、分桶
可以理解簡介加索引,可以提高查詢速度
4.合理設定map和reduce數
4.1輸入資料量大增加map數
當輸入的檔案的資料很大,業務複雜,map執行的很慢,可以考慮增加map的數量,減少每個map處理的資料,提高任務執行效率。
增加map數的方法:
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,調整maxSize最大值。讓maxSize最大值低於blocksize就可以增加map的個數。
案例實操
1)執行查詢
hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1
2)設定最大切片值為100個位元組
hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100;
hive (default)> select count(*) from emp;
Hadoop job information for Stage-1: number of mappers: 6; number of reducers: 1
4.2小檔案合併
1)在map執行前合併小檔案,減少map數:CombineHiveInputFormat具有對小檔案進行合併的功能(系統預設的格式)。HiveInputFormat沒有對小檔案合併功能。
set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
2)在Map-Reduce的任務結束時合併小檔案的設定:
在map-only任務結束時合併小檔案,預設true
SET hive.merge.mapfiles = true;
在map-reduce任務結束時合併小檔案,預設false
SET hive.merge.mapredfiles = true;
合併檔案的大小,預設256M
SET hive.merge.size.per.task = 268435456;
當輸出檔案的平均大小小於預設的256M時,啟動一個獨立的map-reduce任務進行檔案merge
SET hive.merge.smallfiles.avgsize = 16777216;
4.3合理設定reduce數
1)調整reduce個數法一
(1)每個Reduce處理的資料量預設是256MB
hive.exec.reducers.bytes.per.reducer=256000000
(2)每個任務最大的reduce數,預設為1009
hive.exec.reducers.max=1009
(3)計算reducer數的公式
N=min(引數2,總輸入資料量/引數1)
2)調整reduce個數法二
在hadoop的mapred-default.xml檔案中修改
設定每個job的Reduce個數
set mapreduce.job.reduces = 15;
3)reduce個數並不是越多越好
(1)過多的啟動和初始化reduce也會消耗時間和資源;
(2)另外,有多少個reduce,就會有多少個輸出檔案,如果生成了很多個小檔案,那麼如果這些小檔案作為下一個任務的輸入,則也會出現小檔案過多的問題;
在設定reduce個數的時候也需要考慮這兩個原則:處理大資料量利用合適的reduce數;使單個reduce任務處理資料量大小要合適;
5.並行執行
Hive會將一個查詢轉化成一個或者多個階段。這樣的階段可以是MapReduce階段、抽樣階段、合併階段、limit階段。或者Hive執行過程中可能需要的其他階段。預設情況下,Hive一次只會執行一個階段。不過,某個特定的job可能包含眾多的階段,而這些階段可能並非完全互相依賴的,也就是說有些階段是可以並行執行的,這樣可能使得整個job的執行時間縮短。不過,如果有更多的階段可以並行執行,那麼job可能就越快完成。
通過設定引數hive.exec.parallel值為true,就可以開啟併發執行。不過,在共享叢集中,需要注意下,如果job中並行階段增多,那麼叢集利用率就會增加。
set hive.exec.parallel=true; //開啟任務並行執行
set hive.exec.parallel.thread.number=16; //同一個sql允許最大並行度,預設為8。
當然,得是在系統資源比較空閒的時候才有優勢,否則,沒資源,並行也起不來。
6.嚴格模式
Hive可以通過設定防止一些危險操作
1)分割槽表不使用分割槽過濾
將hive.strict.checks.no.partition.filter設定為true時,對於分割槽表,除非where語句中含有分割槽欄位過濾條件來限制範圍,否則不允許執行。換句話說,就是使用者不允許掃描所有分割槽。進行這個限制的原因是,通常分割槽表都擁有非常大的資料集,而且資料增加迅速。沒有進行分割槽限制的查詢可能會消耗令人不可接受的巨大資源來處理這個表。
2)使用order by沒有limit過濾
將hive.strict.checks.orderby.no.limit設定為true時,對於使用了order by語句的查詢,要求必須使用limit語句。因為order by為了執行排序過程會將所有的結果資料分發到同一個Reducer中進行處理,強制要求使用者增加這個LIMIT語句可以防止Reducer額外執行很長一段時間。
3)笛卡爾積
將hive.strict.checks.cartesian.product設定為true時,會限制笛卡爾積的查詢。對關係型資料庫非常瞭解的使用者可能期望在 執行JOIN查詢的時候不使用ON語句而是使用where語句,這樣關係資料庫的執行優化器就可以高效地將WHERE語句轉化成那個ON語句。不幸的是,Hive並不會執行這種優化,因此,如果表足夠大,那麼這個查詢就會出現不可控的情況。
7.JVM重用
開啟uber模式,實現jvm重用。預設情況下,每個Task任務都需要啟動一個jvm來執行,如果Task任務計算的資料量很小,我們可以讓同一個Job的多個Task執行在一個Jvm中,不必為每個Task都開啟一個Jvm.