Hive日常調優3

3.1 Fetch抓取

Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計算。例如:SELECT * FROM orders;在這種情況下,Hive可以簡單地讀取employee對應的存儲目錄下的文件,然後輸出查詢結果到控制檯。

hive-default.xml.template文件中hive.fetch.task.conversion默認是more,老版本hive默認是minimal,該屬性修改爲more以後,在全局查找、字段查找、limit查找等都不走mapreduce。

案例實操:

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;

3.2 本地模式

大多數的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 dept;

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 dept;

Time taken: 20.09 seconds, Fetched: 14 row(s)

3.3 表的優化

2.3.1 小表、大表Join

將key相對分散,並且數據量小的表放在join的左邊,這樣可以有效減少內存溢出錯誤發生的機率;再進一步,可以使用Group讓小的維度表(1000條以下的記錄條數)先進內存。在map端完成reduce。

實際測試發現:新版的hive已經對小表JOIN大表和大表JOIN小表進行了優化。小表放在左邊和右邊已經沒有明顯區別。

案例實操

(0)需求:測試大表JOIN小表和小表JOIN大表的效率
(1)建大表、小表和JOIN後表的語句

// 創建大表
create table big_table(id bigint, time bigint, uid string, keyword string) 
row format delimited fields terminated by '\t';

// 創建小表
create table small_table(id bigint, time bigint, uid string, keyword string) 
row format delimited fields terminated by '\t';

// 創建join後表的語句
create table join_table(id bigint, time bigint, uid string, keyword string) 
row format delimited fields terminated by '\t';

(2)分別向大表和小表中導入數據

hive (default)> load data local inpath '/opt/module/datas/big_table' into table big_table;
hive (default)>load data local inpath '/opt/module/datas/small_table' into table small_table;

(3)關閉mapjoin功能(默認是打開的)

set hive.auto.convert.join = false;

(4)執行小表JOIN大表語句

insert overwrite table join_table
select b.id, b.time, b.uid, b.keyword
from small_table s
left join big_table b
on b.id = s.id;

Time taken: 35.921 seconds

(5)執行大表JOIN小表語句

insert overwrite table join_table
select b.id, b.time, b.uid, b.keyword
from big_table b
left join small_table s
on s.id = b.id;

Time taken: 34.196 seconds

3.4 Key的處理

1)有時join超時是因爲某些key對應的數據太多,而相同key對應的數據都會發送到相同的reducer上,從而導致內存不夠。此時我們應該仔細分析這些異常的key,很多情況下,這些key對應的數據是異常數據,我們需要在SQL語句中進行過濾。
2)有時雖然某個key爲空對應的數據很多,但是相應的數據不是異常數據,必須要包含在join的結果中,此時我們可以表a中key爲空的字段賦一個隨機的值,使得數據隨機均勻地分不到不同的reducer上。

不隨機分佈空null值:

(1)設置5個reduce個數
set mapreduce.job.reduces = 5;

(2)JOIN兩張表
insert overwrite table join_table
select n.* from null_id_table n left join ori b on n.id = b.id;

結果就是出現裏數據傾斜,數據量越大越明顯。

隨機分佈空null值:

(1)設置5個reduce個數
set mapreduce.job.reduces = 5;

(2)JOIN兩張表
insert overwrite table join_table
select n.* from null_id_table n full join ori o on
case when n.id is null then concat('hive', rand()) else n.id end = o.id;

3.5 MapJoin

如果不指定MapJoin或者不符合MapJoin的條件,那麼Hive解析器會將Join操作轉換成Common Join,即:在Reduce階段完成join。容易發生數據傾斜。可以用MapJoin把小表全部加載到內存在map端進行join,避免reducer處理。
1)開啓MapJoin參數設置:

設置自動選擇Mapjoin
set hive.auto.convert.join = true;  // 默認爲true

大表小表的閾值設置(默認25M一下認爲是小表):
set hive.mapjoin.smalltable.filesize=25000000;

3.6 Group By

默認情況下,Map階段同一Key數據分發給一個reduce,當一個key數據過大時就傾斜了。
並不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進行部分聚合,最後在Reduce端得出最終結果。
1)開啓Map端聚合參數設置

// 是否在Map端進行聚合,默認爲True
hive.map.aggr = true
// 在Map端進行聚合操作的條目數目
hive.groupby.mapaggr.checkinterval = 100000
// 有數據傾斜的時候進行負載均衡(默認是false)
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.7 Count(Distinct) 去重統計

數據量小的時候無所謂,數據量大的情況下,由於COUNT DISTINCT操作需要用一個Reduce Task來完成,這一個Reduce需要處理的數據量太大,就會導致整個Job很難完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換:

hive (default)> select count(id) from (select id from bigtable group by id) a;

3.8 笛卡爾積

儘量避免笛卡爾積,join的時候不加on條件,或者無效的on條件,Hive只能使用1個reducer來完成笛卡爾積。

3.9 並行執行

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。

當然,得是在系統資源比較空閒的時候纔有優勢,否則,沒資源,並行也起不來。

3.10 嚴格模式

Hive提供了一個嚴格模式,可以防止用戶執行那些可能意向不到的不好的影響的查詢。
通過設置屬性hive.mapred.mode值爲默認是非嚴格模式nonstrict 。開啓嚴格模式需要修改hive.mapred.mode值爲strict,開啓嚴格模式可以禁止3種類型的查詢。

<property>
<name>hive.mapred.mode</name>
<value>strict</value>
</property>

1)對於分區表,除非where語句中含有分區字段過濾條件來限制範圍,否則不允許執行。換句話說,就是用戶不允許掃描所有分區。進行這個限制的原因是,通常分區表都擁有非常大的數據集,而且數據增加迅速。沒有進行分區限制的查詢可能會消耗令人不可接受的巨大資源來處理這個表。
2)對於使用了order by語句的查詢,要求必須使用limit語句。因爲order by爲了執行排序過程會將所有的結果數據分發到同一個Reducer中進行處理,強制要求用戶增加這個LIMIT語句可以防止Reducer額外執行很長一段時間。
3)限制笛卡爾積的查詢。對關係型數據庫非常瞭解的用戶可能期望在執行JOIN查詢的時候不使用ON語句而是使用where語句,這樣關係數據庫的執行優化器就可以高效地將WHERE語句轉化成那個ON語句。不幸的是,Hive並不會執行這種優化,因此,如果表足夠大,那麼這個查詢就會出現不可控的情況。

3.11 JVM重用

JVM重用是Hadoop調優參數的內容,其對Hive的性能具有非常大的影響,特別是對於很難避免小文件的場景或task特別多的場景,這類場景大多數執行時間都很短。
Hadoop的默認配置通常是使用派生JVM來執行map和Reduce任務的。這時JVM的啓動過程可能會造成相當大的開銷,尤其是執行的job包含有成百上千task任務的情況。JVM重用可以使得JVM實例在同一個job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中進行配置。通常在10-20之間,具體多少需要根據具體業務場景測試得出。

<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is no limit.
</description>
</property>

這個功能的缺點是,開啓JVM重用將一直佔用使用到的task插槽,以便進行重用,直到任務完成後才能釋放。如果某個“不平衡的”job中有某幾個reduce task執行的時間要比其他Reduce task消耗的時間多的多的話,那麼保留的插槽就會一直空閒着卻無法被其他的job使用,直到所有的task都結束了纔會釋放。

3.12 執行計劃(Explain)

1)基本語法

EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query

2)案例實操
(1)查看下面這條語句的執行計劃

hive (default)> explain select * from emp;
hive (default)> explain select deptno, avg(sal) avg_sal from emp group by deptno;

(2)查看詳細執行計劃

hive (default)> explain extended select * from emp;
hive (default)> explain extended select deptno, avg(sal) avg_sal from emp group by deptno;

要清楚每個stage發生了什麼:
在這裏插入圖片描述

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