場景一 .去重場景問題
1)? UNION -- UNION ALL 之間的區(qū)別,如何取舍:UNION 會多出一個(gè)Reduce 流程。這也不難理,為什么在無去重需求下,使用 UNION ALL 而不是 UNION
2)? DISTINCT 替代方式 GROUP BY:
優(yōu)化原理:
我們先說下為什么大數(shù)據(jù)集下? 先 GROUP BY 再COUNT 的效率 要優(yōu)于 直接 COUNT(DISTINCT ...) .
因?yàn)?COUNT(DISTINCT ...)? , 會把相關(guān)的列組成一個(gè)key 傳入到 Reducer 中。即 count(DISTINCT KEY._col0:0._col0, KEY._col0:0._col1, KEY._col0:0._col2) |? ?這樣需要在 一個(gè) Reducer 中?,完成全排序并去重。
先GROUP BY 再去 COUNT ,則GROUP BY 可以 將不同的KEY , 分發(fā)到多個(gè) Reducer 中,在 GROUP BY流程中完成了去重。此時(shí),去重時(shí)并不會把數(shù)據(jù)放入到 一個(gè) Reducer 中,利用了分布式的優(yōu)勢。這個(gè)去重效率更高。在下一步 COUNT 階段,再將上一步奏 GROUP BY 去重后的 KEY , 進(jìn)行統(tǒng)計(jì)計(jì)算。
所以大數(shù)據(jù)量下 先GROUP BY ,再去 COUNT? ? 效率比? COUNT(DISTINCT)? 更高。
我們對比下上述的小數(shù)據(jù)量運(yùn)行結(jié)果:
EXPLAIN 中 :COUNT(DISTINCT )? 比??先GROUP BY 再 COUNT? 的階段少?。因?yàn)?GROUP BY 已經(jīng)是一個(gè) MR STAGE,? 而 COUNT 是另一個(gè) STAGE.
運(yùn)行時(shí)間上 :可以看到兩者并無差別,甚至? COUNT(DISTINCT ) 總時(shí)間小于????先GROUP BY 再 COUNT。這是因?yàn)?,運(yùn)行一個(gè) STAGE 需要申請資源,開辟資源,有時(shí)間成本。故小數(shù)據(jù)量下 , 先GROUP BY 再 COUNT 時(shí)間多于?COUNT(DISTINCT ) , 主要是花費(fèi)在 申請資源,創(chuàng)建容器的時(shí)間上。并且 總運(yùn)行時(shí)間??COUNT(DISTINCT ) 小于??先GROUP BY 再 COUNT
產(chǎn)生上述結(jié)果的原因,還是因?yàn)閿?shù)據(jù)集大小的問題。即 一個(gè) Reducer 全局排序的時(shí)間成本,與劃分多個(gè)作業(yè)階段申請資源的成本的比較 ?。。?/p>
場景二.減少JOB的數(shù)量
1) 巧妙的使用 UNION ALL 減少 JOB 數(shù)量:
低效寫法:SELECT
'a' AS type
,COUNT(1) AS num
FROM datacube_salary_basic_aggr AS a
UNION ALL
SELECT
'b' AS type
,COUNT(1) AS num
FROM datacube_salary_company_aggr AS b
高效寫法:
SELECT
type
,COUNT(1)
FROM
(
SELECT
'a' AS type
,total_salary
FROM datacube_salary_basic_aggr AS a
UNION ALL
SELECT
'b' AS type
,total_salary
FROM datacube_salary_company_aggr AS b
) AS tmp
GROUP BY
type
這里為什么比上面的寫法劃分的階段數(shù)量更少呢 ?因?yàn)槲覀兿劝阉袛?shù)據(jù)UNION ALL了之后,再去做的統(tǒng)計(jì),相當(dāng)于多個(gè)表的數(shù)據(jù)利用 type 作為區(qū)分,一次掃描了進(jìn)來,所以效率更高。但是相應(yīng)的這個(gè)STAGE 階段需要的Mapper 數(shù)量也更多,畢竟我們是一下掃描 的4張表的數(shù)據(jù)?。
2) 利用多表相同的JOIN 關(guān)聯(lián)條件字段,去減少 JOB 的數(shù)量
場景三:合理控制并發(fā)
開啟任務(wù)并行執(zhí)行:?set hive.exec.parallel=true;
允許并行任務(wù)的最大線程數(shù):?set hive.exec.parallel.thread.number=8;
場景四:控制mapper和reducer端個(gè)數(shù)及mapreduce輸出文件大小
mapper:
(1)如果想增加map個(gè)數(shù),則設(shè)置mapred.map.tasks 為一個(gè)較大的值。
(2)如果想減小map個(gè)數(shù),則設(shè)置mapred.min.split.size 為一個(gè)較大的值。
(3)如果輸入中有很多小文件,依然想減少map個(gè)數(shù),則需要將小文件merge 為大文件,然后使用準(zhǔn)則2。
reducer:
每個(gè)Reduce處理的數(shù)據(jù)量:set hive.exec.reducers.bytes.per.reducer=500000000;
500,000,000 ~= 500M;
指定Reduce數(shù)量:set mapred.reduce.tasks=20;
mapreduce輸出文件大?。?br>
在Map-only的任務(wù)結(jié)束時(shí),合并小文件
set hive.merge.mapfiles=true
在Map-Reduce的任務(wù)結(jié)束時(shí)合并小文件
set hive.merge.mapredfiles=true
合并文件的大小
set hive.merge.size.per.task=256000000;
256,000,000 ~= 256M;
輸出文件的平均大小小于該值時(shí),啟動一個(gè)獨(dú)立的map-reduce任務(wù)進(jìn)行文件合并
set hive.merge.smallfiles.avgsize=16000000;
16,000,000 ~= 16M;
場景5:排序問題
1) 合理使用 ORDER BY 與 SORT BY , 在兩者之間做取舍
?應(yīng)該盡量避免使用? ORDER BY ,ORDER BY 會在全局進(jìn)行排序。會單獨(dú)增加一個(gè)作業(yè),在全局進(jìn)行排序。并且在排序中,數(shù)據(jù)會被分放在一個(gè)Reducer 中。SORT BY 只是在每一個(gè)?reducer 中,進(jìn)行局部的排序。
2) 通過使用 LIMIT 限制排序的輸出
?通過 使用SORT BY +??LMIT N , 我們只需要每個(gè) Reduce 控制前N 條記錄即可。然后我們在總的 M個(gè) Reduce 中再去選取其中的 前N 個(gè)數(shù)據(jù)就可以找到前 N 排名的數(shù)據(jù)了。
Tips
1) 使用 SORT BY + LIMIT N 的方式會比 ORDER BY 多一個(gè)JOB。所以,在使用 SORT BY + LIMIT 的方式,我們也要注意數(shù)據(jù)量的規(guī)模
2) 據(jù)說每個(gè)Reduce 取前N 條記錄,使用的是冒泡排序。
場景六:通過讓MAP 端, 多去承擔(dān)任務(wù), 去減少 Reducer 的計(jì)算成本 和 數(shù)據(jù)傳輸成本
1、例子中的小表參與join,沒使用map join時(shí),會導(dǎo)致數(shù)據(jù)傾斜嚴(yán)重。某個(gè)reduce上落太多數(shù)據(jù),reduce時(shí)內(nèi)存會嚴(yán)重占用,甚至不足。
2、不等連接時(shí),reduce會進(jìn)行笛卡兒積,效率很低。
3、使用mapjoin時(shí)還要注意,用作join的關(guān)聯(lián)字段的字段類型最好要一致。?
使用map join后 ?join操作會在map階段完成。
2)? MAP AGGR , 在 Map 端進(jìn)行預(yù)聚合
我們在做 GROUP BY?,? DISTINCT 這些都是可以在 Map 端進(jìn)行預(yù)聚合的,
Map端聚合設(shè)置的參數(shù)
set hive.map.aggr=true;
