1.Hive自己如何確定reduce數(shù):
reduce個數(shù)的設定極大影響任務執(zhí)行效率养铸,不指定reduce個數(shù)的情況下稽穆,hive會猜測確定一個reduce個數(shù)瓜客,基于以下兩個設定:
hive.exec.reducers.bytes.per.reducer(每個reduce任務處理的數(shù)據(jù)量,默認為1000^3=1G)
hive.exec.reducers.max(每個任務最大的reduce數(shù)了嚎,默認為999)
計算reducer數(shù)的公式很簡單N=min(參數(shù)2趁怔,總輸入數(shù)據(jù)量/參數(shù)1)
即,如果reduce的輸入(map的輸出)總大小不超過1G,那么只會有一個reduce任務;
如:select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;
/group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04 總大小為9G多碎税,因此這句有10個reduce
2. 調整reduce個數(shù)方法一:
調整hive.exec.reducers.bytes.per.reducer參數(shù)的值;
set hive.exec.reducers.bytes.per.reducer=500000000; (500M)
select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt; 這次有20個reduce
3. 調整reduce個數(shù)方法二馏锡;
set mapred.reduce.tasks = 15;
select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt;這次有15個reduce
4. reduce個數(shù)并不是越多越好雷蹂;
同map一樣,啟動和初始化reduce也會消耗時間和資源杯道;
另外匪煌,有多少個reduce,就會有多少個輸出文件,如果生成了很多個小文件党巾,那么如果這些小文件作為下一個任務的輸入虐杯,則也會出現(xiàn)小文件過多的問題;
5. 什么情況下只有一個reduce昧港;
很多時候你會發(fā)現(xiàn)任務中不管數(shù)據(jù)量多大擎椰,不管你有沒有設置調整reduce個數(shù)的參數(shù),任務中一直都只有一個reduce任務创肥;
其實只有一個reduce任務的情況达舒,除了數(shù)據(jù)量小于hive.exec.reducers.bytes.per.reducer參數(shù)值的情況外值朋,還有以下原因:
a) 沒有group by的匯總,比如把select pt,count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04' group by pt; 寫成 select count(1) from popt_tbaccountcopy_mes where pt = '2012-07-04';
這點非常常見巩搏,希望大家盡量改寫昨登。
b) 用了Order by
c) 有笛卡爾積
通常這些情況下,除了找辦法來變通和避免贯底,我暫時沒有什么好的辦法丰辣,因為這些操作都是全局的,所以Hadoop不得不用一個reduce去完成禽捆;
同樣的笙什,在設置reduce個數(shù)的時候也需要考慮這兩個原則:使大數(shù)據(jù)量利用合適的reduce數(shù);使單個reduce任務處理合適的數(shù)據(jù)量胚想;
Hive是將符合SQL語法的字符串解析生成可以在hadoop上執(zhí)行的MapReduce的工具琐凭。
使用Hive盡量按照分布式計算的一些特點來設計sql,和傳統(tǒng)關系型數(shù)據(jù)庫有區(qū)別浊服,
所以需要去掉原有關系型數(shù)據(jù)庫下開發(fā)的一些固有思維统屈。
基本原則:
1:盡量盡早地過濾數(shù)據(jù),減少每個階段的數(shù)據(jù)量,對于分區(qū)表要加分區(qū)牙躺,同時只選擇需要使用到的字段
select ... from A
join B
on A.key = B.key
where A.userid>10
and B.userid<10
and A.dt='20120417'
and B.dt='20120417';
應該改寫為:
select .... from (select .... from A
where dt='201200417'
and userid>10
) a
join ( select .... from B
where dt='201200417'
and userid < 10
) b
on a.key = b.key;
2:盡量原子化操作愁憔,盡量避免一個SQL包含復雜邏輯
可以使用中間表來完成復雜的邏輯
drop table if exists tmp_table_1;
create table if not exists tmp_table_1 as
select ......;
drop table if exists tmp_table_2;
create table if not exists tmp_table_2 as
select ......;
drop table if exists result_table;
create table if not exists result_table as
select ......;
drop table if exists tmp_table_1;
drop table if exists tmp_table_2;
3:單個SQL所起的JOB個數(shù)盡量控制在5個以下
4:慎重使用mapjoin,一般行數(shù)小于2000行,大小小于1M(擴容后可以適當放大)的表才能使用,小表要注意放在join的左邊(目前TCL里面很多都小表放在join的右邊)孽拷。
否則會引起磁盤和內(nèi)存的大量消耗
5:寫SQL要先了解數(shù)據(jù)本身的特點惩淳,如果有join ,group操作的話,要注意是否會有數(shù)據(jù)傾斜
如果出現(xiàn)數(shù)據(jù)傾斜乓搬,應當做如下處理:
set hive.exec.reducers.max=200;
set mapred.reduce.tasks= 200;---增大Reduce個數(shù)
set hive.groupby.mapaggr.checkinterval=100000 ;--這個是group的鍵對應的記錄條數(shù)超過這個值則會進行分拆,值根據(jù)具體數(shù)據(jù)量設置
set hive.groupby.skewindata=true; --如果是group by過程出現(xiàn)傾斜 應該設置為true
set hive.skewjoin.key=100000; --這個是join的鍵對應的記錄條數(shù)超過這個值則會進行分拆,值根據(jù)具體數(shù)據(jù)量設置
set hive.optimize.skewjoin=true;--如果是join 過程出現(xiàn)傾斜 應該設置為true
6:如果union all的部分個數(shù)大于2思犁,或者每個union部分數(shù)據(jù)量大,應該拆成多個insert into 語句进肯,實際測試過程中激蹲,執(zhí)行時間能提升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 ...;