Hive調(diào)優(yōu)策略
Hive作為大數(shù)據(jù)領(lǐng)域常用的數(shù)據(jù)倉庫組件,在設(shè)計(jì)和開發(fā)階段需要注意效率漫萄。
影響Hive效率的不僅僅是數(shù)據(jù)量過大;數(shù)據(jù)傾斜堆生、數(shù)據(jù)冗余虐译、job(小文件多)或I/O過多、MapReduce分配不合理等因素都對(duì)Hive的效率有影響鹅龄。
對(duì)Hive的調(diào)優(yōu)既包含對(duì)HiveQL語句本身的優(yōu)化揩慕,也包含Hive配置項(xiàng)和MR方面的調(diào)整。
從以下幾個(gè)方面調(diào)優(yōu):
1扮休、架構(gòu)調(diào)優(yōu)
2迎卤、參數(shù)調(diào)優(yōu)
3、SQL優(yōu)化
架構(gòu)優(yōu)化
執(zhí)行引擎
Hive支持多種執(zhí)行引擎玷坠,分別是MR蜗搔、Tez、Spark八堡、Flink樟凄,可以通過hive-site.xml文件中的hive.execution.engine屬性配置。
Tez是一個(gè)構(gòu)建于YARN之上的支持復(fù)雜的DAG(有向無環(huán)圖)任務(wù)的數(shù)據(jù)處理框 架兄渺。由Hontonworks開源缝龄,將MapReduce的過程拆分成若干個(gè)子過程,同時(shí)可以 把多個(gè)mapreduce任務(wù)組合成一個(gè)較大的DAG任務(wù),減少了MapReduce之間的文件存儲(chǔ)二拐,同時(shí)合理組合其子過程從而大幅提升MR作業(yè)的性能服鹅。
優(yōu)化器
與關(guān)系型數(shù)據(jù)庫類似,Hive在真正執(zhí)行的時(shí)候百新,會(huì)先先通過解釋器
生成AST抽象語法樹企软,然后再通過編譯器生成邏輯執(zhí)行計(jì)劃,再通過優(yōu)化器進(jìn)行優(yōu)化饭望,優(yōu)化后通過執(zhí)行器生成物理執(zhí)行計(jì)劃仗哨。而Hive有兩種優(yōu)化器:
Vectorize(矢量化優(yōu)化器)和Cost-Based Optimization(CBO成本優(yōu)化器)
- 矢量化查詢優(yōu)化(向量化優(yōu)化器)
矢量化查詢(要求執(zhí)行引擎為Tez)執(zhí)行通過一次批量執(zhí)行1024行,而不是每行一行來提高掃描铅辞、聚合厌漂、過濾器和和鏈接等操作的性能,這個(gè)功能明顯縮短查詢執(zhí)行時(shí)間
## 默認(rèn) false
set hive.vectorized.execution.enabled = true;
## 默認(rèn) false
set hive.vectorized.execution.reduce.enabled = true;
備注:
- 要使用矢量化查詢執(zhí)行斟珊,必須用ORC格式存儲(chǔ)數(shù)據(jù)
- 求執(zhí)行引擎為Tez
- 成本優(yōu)化器
Hive的CBO是基于Apache Calcite的苇倡,Hive的CBO通過查詢成本(有analyze收集的統(tǒng)計(jì)信息)會(huì)生成有效率的執(zhí)行計(jì)劃,最終會(huì)較少執(zhí)行的時(shí)間和資源利用囤踩,使用CBO的配置如下:
--從 v0.14.0默認(rèn) true
SET hive.cbo.enable=true;
-- 默認(rèn)false
SET hive.compute.query.using.stats=true;
-- 默認(rèn)false
SET hive.stats.fetch.column.stats=true;
-- 默認(rèn)true
SET hive.stats.fetch.partition.stats=true;
定期執(zhí)行表(分析的命令:analyze)的分析旨椒,分析后的數(shù)據(jù)放在元數(shù)據(jù)庫中。
低版本情況下堵漱,小表在前的確效率高综慎,高版本優(yōu)化器已經(jīng)做了優(yōu)化。是因?yàn)樾”淼臄?shù)據(jù)可能會(huì)放到內(nèi)存里面勤庐,大表的數(shù)據(jù)內(nèi)存存不下就會(huì)導(dǎo)致效率低示惊。
把重復(fù)關(guān)聯(lián)鍵少的表放在join前面做關(guān)聯(lián)可以提高join的效率
分區(qū)表
對(duì)于一個(gè)比較大的表,將其設(shè)計(jì)成分區(qū)表愉镰,可以提升查詢的性能米罚,對(duì)于一個(gè)特定分區(qū)的查詢,只會(huì)加載對(duì)應(yīng)分區(qū)路徑的數(shù)據(jù)文件岛杀,所以執(zhí)行速度比較快
分區(qū)字段的選擇阔拳,避免層級(jí)較深的分區(qū),否則會(huì)造成太多的字文件夾类嗤,常見的分區(qū)字段:
- 日期或時(shí)間。如 year辨宠、month遗锣、day或者h(yuǎn)our,當(dāng)表中存在時(shí)間或者日期字段時(shí)
- 地理問題嗤形。如國家精偿、省份、城市等
- 業(yè)務(wù)邏輯。如部門笔咽、銷售區(qū)域搔预、客戶等等
分桶表
與分區(qū)表類似,分桶表的組織方式是將HDFS上的文件分割成多個(gè)文件叶组。
分桶可以加快數(shù)據(jù)采樣拯田,也可以提升join的性能,join的字段是分桶字段甩十,因?yàn)榉滞翱梢源_保某一個(gè)key對(duì)應(yīng)的數(shù)據(jù)在一個(gè)特定的桶內(nèi)(文件)船庇,巧妙的選擇分桶字段,可以大幅度提升join性能侣监。
通常情況下鸭轮,分桶字段可以選擇經(jīng)常用過濾操作或者join操作的字段
文件格式
在HiveQL的create table語句中,可以使用 stored as ... 指定表的存儲(chǔ)格式橄霉。 Hive表支持的存儲(chǔ)格式有TextFile窃爷、SequenceFile、RCFile姓蜂、ORC吞鸭、Parquet等。
存儲(chǔ)格式一般需要根據(jù)業(yè)務(wù)進(jìn)行選擇覆糟,生產(chǎn)環(huán)境中絕大多數(shù)表都采用TextFile刻剥、 ORC、Parquet存儲(chǔ)格式之一滩字。
TextFile是最簡單的存儲(chǔ)格式造虏,它是純文本記錄,也是Hive的默認(rèn)格式麦箍。其磁盤開銷 大漓藕,查詢效率低,更多的是作為跳板來使用挟裂。RCFile享钞、ORC、Parquet等格式的表都不能由文件直接導(dǎo)入數(shù)據(jù)诀蓉,必須由TextFile來做中轉(zhuǎn)栗竖。
Parquet和ORC都是Apache旗下的開源列式存儲(chǔ)格式。列式存儲(chǔ)比起傳統(tǒng)的行式存 儲(chǔ)更適合批量OLAP查詢渠啤,并且也支持更好的壓縮和編碼狐肢。選擇Parquet的原因主要 是它支持Impala查詢引擎,并且對(duì)update沥曹、delete和事務(wù)性操作需求很低份名。
數(shù)據(jù)壓縮
壓縮技術(shù)可以減少map與reduce之間的數(shù)據(jù)傳輸碟联,從而可以提升查詢性能,關(guān)于壓 縮的配置可以在hive的命令行中或者h(yuǎn)ive-site.xml文件中進(jìn)行配置僵腺。
-- 默認(rèn)是false
SET hive.exec.compress.intermediate=true
開啟壓縮之后鲤孵,可以選擇下面的壓縮格式:
關(guān)于壓縮的編碼器可以通過mapred-site.xml, hive-site.xml進(jìn)行配置,也可以通過 命令行進(jìn)行配置辰如,如:
-- 中間結(jié)果壓縮
SET hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;
-- 輸出結(jié)果壓縮
SET hive.exec.compress.output=true;
SET mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodc
設(shè)計(jì)階段要考慮的優(yōu)化點(diǎn):
1普监、執(zhí)行引擎
2、優(yōu)化器
3丧没、分區(qū)鹰椒、分桶
4、文件格式
5呕童、數(shù)據(jù)壓縮
參數(shù)優(yōu)化
本地模式
當(dāng)Hive處理的數(shù)據(jù)量較小的時(shí)漆际,啟動(dòng)分布式處理數(shù)據(jù)就會(huì)顯得浪費(fèi),因?yàn)榭赡軉?dòng)時(shí)間比處理數(shù)據(jù)時(shí)間還要長夺饲,Hive支持將作業(yè)動(dòng)態(tài)的轉(zhuǎn)為本地模式奸汇,需要使用下面的配置:
-- 默認(rèn) false
SET hive.exec.mode.local.auto=true;
-- 默認(rèn)128M
SET hive.exec.mode.local.auto.inputbytes.max=50000000;
-- 默認(rèn) 4
SET hive.exec.mode.local.auto.input.files.max=5;
一個(gè)作業(yè)只要滿足下面的條件,會(huì)啟用本地模式
- 輸入文件的大小小于 hive.exec.mode.local.auto.inputbytes.max 配置的大小
- map任務(wù)的數(shù)量小于 hive.exec.mode.local.auto.input.files.max 配置的大小
- reduce任務(wù)的數(shù)量是1或者0
嚴(yán)格模式
所謂嚴(yán)格模式就是不允許執(zhí)行3種有風(fēng)險(xiǎn)的HQL語句
- 查詢分區(qū)表的時(shí)候不限定分區(qū)列的語句
- 兩個(gè)表join產(chǎn)生了笛卡爾積
- 用order by 來排序往声,但沒有指定limit
要開啟嚴(yán)格模式擂找,需要將參數(shù)要開啟嚴(yán)格模式,需要將參數(shù) hive.mapred.mode
設(shè)為strict(缺省值)浩销。
該參數(shù)可以不在參數(shù)文件中定義贯涎,在執(zhí)行SQL之前設(shè)置(set hive.mapred.mode=nostrict ),即在當(dāng)前SQL不是嚴(yán)格模式。
JVM重用
默認(rèn)情況下慢洋,Hadoop會(huì)為為一個(gè)map或者reduce啟動(dòng)一個(gè)JVM塘雳,這樣可以并行執(zhí)行map和reduce。
當(dāng)map或者reduce是那種僅運(yùn)行幾秒鐘的輕量級(jí)作業(yè)時(shí)普筹,JVM啟動(dòng)進(jìn)程所耗費(fèi)的時(shí) 間會(huì)比作業(yè)執(zhí)行的時(shí)間還要長败明。Hadoop可以重用JVM,通過共享JVM以串行而非并行的方式運(yùn)行map或者reduce太防。
JVM的重用適用于同一個(gè)作業(yè)的map和reduce妻顶,對(duì)于不同作業(yè)的task不能夠共享 JVM。如果要開啟JVM重用蜒车,需要配置一個(gè)作業(yè)最大task數(shù)量讳嘱,默認(rèn)值為1,如果設(shè) 置為-1醇王,則表示不限制
# 代表同一個(gè)MR job中順序執(zhí)行的5個(gè)task重復(fù)使用一個(gè)JVM呢燥,減少啟動(dòng)和關(guān)閉的開銷
SET mapreduce.job.jvm.numtasks=5;
這個(gè)功能的缺點(diǎn)是,開啟JVM重用將一直占用使用到的task插槽寓娩,以便進(jìn)行重用,直 到任務(wù)完成后才能釋放。如果某個(gè)“不平衡的”job中有某幾個(gè)reduce task執(zhí)行的時(shí)間 要比其他Reduce task消耗的時(shí)間多的多的話棘伴,那么保留的插槽就會(huì)一直空閑著卻無 法被其他的job使用寞埠,直到所有的task都結(jié)束了才會(huì)釋放。
并行執(zhí)行
Hive的查詢通常會(huì)被轉(zhuǎn)換成一系列的stage焊夸,這些stage之間并不是一直相互依賴 的仁连,可以并行執(zhí)行這些stage,通過下面的方式進(jìn)行配置:
SET hive.exec.parallel=true; -- 默認(rèn)false
SET hive.exec.parallel.thread.number=16; -- 默認(rèn)8
并行執(zhí)行可以增加集群資源的利用率阱穗,如果集群的資源使用率已經(jīng)很高了饭冬,那么并 行執(zhí)行的效果不會(huì)很明顯。
推測(cè)執(zhí)行
在分布式集群環(huán)境下揪阶,因?yàn)槌绦駼ug昌抠、負(fù)載不均衡、資源分布不均等原因鲁僚,會(huì)造成同 一個(gè)作業(yè)的多個(gè)任務(wù)之間運(yùn)行速度不一致炊苫,有些任務(wù)的運(yùn)行速度可能明顯慢于其他任務(wù)(比如一個(gè)作業(yè)的某個(gè)任務(wù)進(jìn)度只有50%,而其他所有任務(wù)已經(jīng)運(yùn)行完畢)冰沙, 則這些任務(wù)會(huì)拖慢作業(yè)的整體執(zhí)行進(jìn)度侨艾。
為了避免這種情況發(fā)生,Hadoop采用了推測(cè)執(zhí)行機(jī)制拓挥,它根據(jù)一定的規(guī)則推測(cè)出 “拖后腿”的任務(wù)唠梨,并為這樣的任務(wù)啟動(dòng)一個(gè)備份任務(wù),讓該任務(wù)與原始任務(wù)同時(shí)處理 同一份數(shù)據(jù)侥啤,并最終選用最先成功運(yùn)行完成任務(wù)的計(jì)算結(jié)果作為最終結(jié)果当叭。
set mapreduce.map.speculative=true
set mapreduce.reduce.speculative=true
set hive.mapred.reduce.tasks.speculative.execution=true
合并小文件
- 在map執(zhí)行前合并小文件,減少map數(shù)
# 缺省參數(shù)
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
- 在Map-Reduce的任務(wù)結(jié)束時(shí)合并小文件
# 在 map-only 任務(wù)結(jié)束時(shí)合并小文件愿棋,默認(rèn)true
SET hive.merge.mapfiles = true;
# 在 map-reduce 任務(wù)結(jié)束時(shí)合并小文件科展,默認(rèn)false
SET hive.merge.mapredfiles = true;
# 合并文件的大小,默認(rèn)256M
SET hive.merge.size.per.task = 268435456;
# 當(dāng)輸出文件的平均大小小于該值時(shí)糠雨,啟動(dòng)一個(gè)獨(dú)立的map-reduce任務(wù)進(jìn)行文件merge
SET hive.merge.smallfiles.avgsize = 16777216;
Fetch模式
Fetch模式是指Hive中對(duì)某些情況的查詢可以不必使用MR計(jì)算才睹,select col1,col2 from tab;
可以簡單地讀取表對(duì)應(yīng)的存儲(chǔ)目錄下的文件,然后輸出查詢結(jié)果到控制臺(tái)甘邀,在開啟fetch模式之后琅攘,在全局查找、字段查找松邪、limit查找等都不啟動(dòng)MR
# Default Value: minimal in Hive 0.10.0 through 0.13.1, more in Hive 0.14.0 and later
set hive.fetch.task.conversion=more
參數(shù)調(diào)整:
1坞琴、本地模式
2、嚴(yán)格模式
3逗抑、JVM重用
4剧辐、并行執(zhí)行
5寒亥、推測(cè)執(zhí)行
6、合并小文件
7荧关、fetch模式(規(guī)避沒有必要的MapReduce)
SQL優(yōu)化
列裁剪和分區(qū)裁剪
列裁剪是在查詢時(shí)至讀取需要的列溉奕,避免查詢select * from tab這種;分區(qū)裁剪就是只讀取需要的分區(qū)忍啤,不需要的分區(qū)不需要讀取出來,分區(qū)表一定要跟上分區(qū)加勤。
select uid, event_type, record_data
from calendar_record_log
where pt_date >= 20190201 and pt_date <= 20190224
and status = 0;
sort by 代替 order by
HiveQL中的order by與其他關(guān)系數(shù)據(jù)庫SQL中的功能一樣,是將結(jié)果按某字段全局排序同波,這會(huì)導(dǎo)致所有map端數(shù)據(jù)都進(jìn)入一reduce中鳄梅,在數(shù)據(jù)量大時(shí)可能會(huì)長時(shí)間計(jì)算不完。
如果使用sort by未檩,那么還是會(huì)視情況啟動(dòng)多個(gè)reducer進(jìn)行排序戴尸,并且保證每個(gè) reducer內(nèi)局部有序。為了控制map端數(shù)據(jù)分配到reducer的key讹挎,往往還要配合 distribute by 一同使用校赤。如果不加 distribute by 的話,map端數(shù)據(jù)就會(huì)隨機(jī)分配到 reducer筒溃。
group by 代替count(distinct)
當(dāng)要統(tǒng)計(jì)某一列的去重?cái)?shù)時(shí)马篮,如果數(shù)據(jù)量很大,count(distinct) 會(huì)非常慢怜奖。原因與 order by類似浑测,count(distinct)邏輯只會(huì)有很少的reducer來處理。此時(shí)可以用 group by 來改寫:
-- 原始SQL
select count(distinct uid)
from tab;
-- 優(yōu)化后的SQL
select count(1)
from (select uid
from tab
group by uid) tmp;
這樣寫會(huì)啟動(dòng)兩個(gè)MR job(單純distinct只會(huì)啟動(dòng)一個(gè))歪玲,所以要確保數(shù)據(jù)量大到啟動(dòng)job的overhead遠(yuǎn)小于計(jì)算耗時(shí)迁央,才考慮這種方法。當(dāng)數(shù)據(jù)集很小或者key的傾斜 比較明顯時(shí)滥崩,group by還可能會(huì)比distinct慢岖圈。
group by配置調(diào)整----map端預(yù)聚合
group by時(shí),如果先起一個(gè)combiner在map端做部分預(yù)聚合钙皮,可以有效減少 shuffle數(shù)據(jù)量蜂科。
-- 默認(rèn)為true
set hive.map.aggr = true
Map端進(jìn)行聚合操作的條目數(shù)
set hive.groupby.mapaggr.checkinterval = 100000
通過 hive.groupby.mapaggr.checkinterval 參數(shù)也可以設(shè)置map端預(yù)聚合的行 數(shù)閾值,超過該值就會(huì)分拆job短条,默認(rèn)值10W导匣。
group by配置調(diào)整----傾斜均衡置頂
group by時(shí)如果某些key對(duì)應(yīng)的數(shù)據(jù)量過大,就會(huì)發(fā)生數(shù)據(jù)傾斜茸时。Hive自帶了一個(gè)均衡數(shù)據(jù)傾斜的配置項(xiàng) hive.groupby.skewindata 贡定,默認(rèn)值false。
其實(shí)現(xiàn)方法是在group by時(shí)啟動(dòng)兩個(gè)MR job。第一個(gè)job會(huì)將map端數(shù)據(jù)隨機(jī)輸入 reducer备恤,每個(gè)reducer做部分聚合,相同的key就會(huì)分布在不同的reducer中射亏。第二 個(gè)job再將前面預(yù)處理過的數(shù)據(jù)按key聚合并輸出結(jié)果命斧,這樣就起到了均衡的效果田晚。
但是国葬,配置項(xiàng)畢竟是死的汇四,單純靠它有時(shí)不能根本上解決問題,建議了解數(shù)據(jù)傾斜 的細(xì)節(jié),并優(yōu)化查詢語句行剂。
join的在基礎(chǔ)優(yōu)化
hive join 的三種方式
- common join
普通連接,在SQL中不特殊指定連接方式使用的都是這種普通連接,兩個(gè)數(shù)據(jù)在做連接之前,會(huì)先去做shuffle撵幽,如下圖,會(huì)將關(guān)聯(lián)id,相同的時(shí)候同一個(gè)區(qū)测垛,再去真正的關(guān)聯(lián)
缺點(diǎn):性能差(性能差的原因:要將數(shù)據(jù)分區(qū),有shuffle)
優(yōu)點(diǎn):操作簡單链快,適應(yīng)性強(qiáng)
- map join
map端連接噪猾,與普通連接的區(qū)別是這個(gè)連接中不會(huì)有reduce階段存在,連接在map端完成
適用場(chǎng)景:大表與小表連接,小表數(shù)據(jù)量應(yīng)該能夠完全加載到內(nèi)存贱田,否則不適用
優(yōu)點(diǎn):在大小表連接時(shí)性能提升明顯,
備注:Hive 0.6 的時(shí)候默認(rèn)認(rèn)為寫在select 后面的是大表,前面的是小表帆离, 或者使用 /+mapjoin(map_table) / select a., b. from a join b on a.id = b.id【要求小表在前麻献,大表之后】
hive 0.7 的時(shí)候這個(gè)計(jì)算是自動(dòng)化的监婶,它首先會(huì)自動(dòng)判斷哪個(gè)是小表煮盼,哪個(gè)是大 表,這個(gè)參數(shù)由(hive.auto.convert.join=true)來控制报破,然后控制小表的大小由 (hive.smalltable.filesize=25000000)參數(shù)控制(默認(rèn)是25M),當(dāng)小表超過這個(gè) 大小帆疟,hive 會(huì)默認(rèn)轉(zhuǎn)化成common join妈嘹。
Hive 0.8.1柬脸,hive.smalltable.filesize => hive.mapjoin.smalltable.filesize 缺點(diǎn):使用范圍較小,只針對(duì)大小表且小表能完全加載到內(nèi)存中的情況。
- bucket map join
分桶連接:Hive 建表的時(shí)候支持hash 分區(qū)通過指定clustered by (col_name,xxx ) into number_buckets buckets 關(guān)鍵字.當(dāng)連接的兩個(gè)表的join key 就是bucket column 的時(shí)候序愚,就可以通過設(shè)置hive.optimize.bucketmapjoin= true 來執(zhí)行優(yōu) 化精刷。
原理:通過兩個(gè)表分桶在執(zhí)行連接時(shí)會(huì)將小表的每個(gè)分桶映射成hash表锈遥,每個(gè)task 節(jié)點(diǎn)都需要這個(gè)小表的所有hash表,但是在執(zhí)行時(shí)只需要加載該task所持有大表分 桶對(duì)應(yīng)的小表部分的hash表就可以侠驯,所以對(duì)內(nèi)存的要求是能夠加載小表中最大的 hash塊即可儒士。
注意點(diǎn):小表與大表的分桶數(shù)量需要是倍數(shù)關(guān)系,這個(gè)是因?yàn)榉滞安呗詻Q定的檩坚,分桶時(shí)會(huì)根據(jù)分桶字段對(duì)桶數(shù)取余后決定哪個(gè)桶的着撩,所以要保證成倍數(shù)關(guān)系。
優(yōu)點(diǎn):比map join對(duì)內(nèi)存的要求降低匾委,能在逐行對(duì)比時(shí)減少數(shù)據(jù)計(jì)算量(不用比對(duì) 小表全量)
缺點(diǎn):只適用于分桶表
利用map join特性
map join特別適合大小表join的情況拖叙。Hive會(huì)將build table和probe table在map端直接完成join過程,消滅了reduce剩檀,效率很高憋沿。
select a.event_type, b.upload_time from calendar_event_code a
inner join (
select event_type, upload_time from calendar_record_log
where pt_date = 20190225
) b on a.event_type < b.event_type;
map join的配置項(xiàng)是 hive.auto.convert.join ,默認(rèn)值true沪猴。
當(dāng)build table大小小于hive.mapjoin.smalltable.filesize 會(huì)啟用map join辐啄, 默認(rèn)值25000000(約25MB)。還有 hive.mapjoin.cache.numrows 运嗜,表示緩存 build table的多少行數(shù)據(jù)到內(nèi)存壶辜,默認(rèn)值25000。
分桶表map join
map join對(duì)分桶表還有特別的優(yōu)化担租。由于分桶表是基于一列進(jìn)行hash存儲(chǔ)的砸民,因此 非常適合抽樣(按桶或按塊抽樣)。它對(duì)應(yīng)的配置項(xiàng)是 hive.optimize.bucketmapjoin 。
傾斜均衡配置項(xiàng)
這個(gè)配置與 group by 的傾斜均衡配置項(xiàng)異曲同工岭参,通過 hive.optimize.skewjoin 來配置反惕,默認(rèn)false。如果開啟了演侯,在join過程中Hive會(huì)將計(jì)數(shù)超過閾值 hive.skewjoin.key (默認(rèn) 100000)的傾斜key對(duì)應(yīng)的行臨時(shí)寫進(jìn)文件中姿染,然后再啟動(dòng)另一個(gè)job做map join生 成結(jié)果。通過 hive.skewjoin.mapjoin.map.tasks 參數(shù)還可以控制第二個(gè)job的 mapper數(shù)量秒际,默認(rèn)10000悬赏。
去掉空值和無意義的值
日志類數(shù)據(jù)中往往會(huì)有一些項(xiàng)沒有記錄到,其值為null娄徊,或者空字符串闽颇、-1等。如果 缺失的項(xiàng)很多寄锐,在做join時(shí)這些空值就會(huì)非常集中兵多,拖累進(jìn)度【備注:這個(gè)字段是連接字段】。
若不需要空值數(shù)據(jù)锐峭,就提前寫 where 語句過濾掉中鼠。需要保留的話,將空值key用隨 機(jī)方式打散沿癞,例如將用戶ID為null的記錄隨機(jī)改為負(fù)值:
select a.uid, a.event_type, b.nickname, b.age from (
select
(case when uid is null then cast(rand()*-10240 as int) else uid end) as uid,
event_type from calendar_record_log
where pt_date >= 20190201
) a left outer join (
select uid,nickname,age from user_info where status = 4 ) b on a.uid = b.uid;
單獨(dú)處理傾斜的key
如果傾斜的 key 有實(shí)際的意義,一般來講傾斜的key都很少矛渴,此時(shí)可以將它們單獨(dú)抽 取出來椎扬,對(duì)應(yīng)的行單獨(dú)存入臨時(shí)表中,然后打上一個(gè)較小的隨機(jī)數(shù)前綴(比如 0~9)具温,最后再進(jìn)行聚合蚕涤。
不要一個(gè)Select語句中,寫太多的Join铣猩。一定要了解業(yè)務(wù)揖铜,了解數(shù)據(jù)。(A0-A9) 分成多條語句达皿,分步執(zhí)行;(A0-A4; A5-A9);先執(zhí)行大表與小表的關(guān)聯(lián);
調(diào)整Map數(shù)
通常情況下天吓,作業(yè)會(huì)通過輸入數(shù)據(jù)的目錄產(chǎn)生一個(gè)或者多個(gè)map任務(wù)。主要因素包括:
- 輸入文件總數(shù)
- 輸入文件大小
- HDFS文件塊大小
Map不是越多也好峦椰,而是合適的才是最好的龄寞。
如果一個(gè)任務(wù)有很多小文件(遠(yuǎn)遠(yuǎn)小于128M),每個(gè)小文件也會(huì)被當(dāng)做成一個(gè)數(shù)據(jù)塊汤功,用一個(gè)MapTask來完成物邑,一個(gè)MapTask啟動(dòng)和初始化時(shí)間遠(yuǎn)遠(yuǎn)大于處理時(shí)間,就會(huì)造成資源浪費(fèi),而且系統(tǒng)中可用的map是有限的色解。
對(duì)于小文件采用的策略是合并小文件茂嗓。
每個(gè)map處理接近128M的文件塊,會(huì)有其他問題嗎科阎。也不一定述吸。
有一個(gè)125M的文件,一般情況下會(huì)用一個(gè)Map Task完成萧恕。假設(shè)這個(gè)文件字段很 少刚梭,但記錄數(shù)卻非常多。如果Map處理的邏輯比較復(fù)雜票唆,用一個(gè)map任務(wù)去做朴读,性 能也不好。
對(duì)于復(fù)雜文件采用的策略是增加 Map 數(shù)
computeSliteSize(max(minSize, min(maxSize, blocksize))) = blocksize
minSize : mapred.min.split.size (默認(rèn)值1)
maxSize : mapred.max.split.size (默認(rèn)值256M)
調(diào)整maxSize最大值走趋。讓maxSize最大值低于blocksize就可以增加map的個(gè)數(shù)衅金。 建議用set的方式,針對(duì)SQL語句進(jìn)行調(diào)整簿煌。
調(diào)整Reduce數(shù)
reducer數(shù)量的確定方法比mapper簡單得多氮唯。使用參數(shù) mapred.reduce.tasks
可以直接設(shè)定reducer數(shù)量。如果未設(shè)置該參數(shù)姨伟,Hive會(huì)進(jìn)行自行推測(cè)惩琉,邏輯如下:
- 參數(shù)hive.exec.reducers.bytes.per.reducer用來設(shè)定每個(gè)reducer能夠處理的最大數(shù)據(jù)量,默認(rèn)值256M
- 參數(shù)hive.exec.reducers.max用來設(shè)定每個(gè)job的最大reducer數(shù)量夺荒,默認(rèn)值999(1.2版本之前)或1009(1.2版本之后)
- 得出reducer數(shù):reducer_num = Min(total_input_size / hive.exec.reducers.bytes.per.reducer,hive.exec.reducers.max )
即: min(輸入總數(shù)據(jù)量 / 256M, 1009)
reducer數(shù)量與輸出文件的數(shù)量相關(guān)瞒渠。如果reducer數(shù)太多,會(huì)產(chǎn)生大量小文件技扼,對(duì) HDFS造成壓力伍玖。如果reducer數(shù)太少,每個(gè)reducer要處理很多數(shù)據(jù)剿吻,容易拖慢運(yùn)行 時(shí)間或者造成OOM窍箍。
Hive優(yōu)化小結(jié)
深入理解 Hadoop 的核心能力,對(duì)Hive優(yōu)化很有幫助丽旅。Hadoop/Hive 處理數(shù)據(jù)過 程椰棘,有幾個(gè)顯著特征:
- 不怕數(shù)據(jù)多,就怕數(shù)據(jù)傾斜
- 對(duì)job數(shù)比較多的作業(yè)運(yùn)行效率相對(duì)比較低魔招,比如即使有幾百行的表晰搀,多次關(guān)聯(lián)多次匯總,產(chǎn)品十幾個(gè)jobs办斑,執(zhí)行時(shí)間也需要較長時(shí)間外恕。MapReduce作業(yè)初始化的時(shí)間是比較長的杆逗。
- 對(duì)sum、count的聚合操作來說鳞疲,不存在數(shù)據(jù)傾斜
- count(distinct) 效率較低罪郊,數(shù)據(jù)量大容易出問題
從大的方面來說,優(yōu)化可以從幾個(gè)方面
- 好的設(shè)計(jì)模型尚洽,事半功倍(該分區(qū)分區(qū)悔橄,該分桶分桶,壓縮腺毫、本地模式)
- 解決數(shù)據(jù)傾斜問題癣疟。僅僅依靠參數(shù)解決數(shù)據(jù)傾斜,是通用的優(yōu)化手段潮酒,收獲有限睛挚。開發(fā)人員應(yīng)該熟悉業(yè)務(wù),了解數(shù)據(jù)規(guī)律急黎,通過業(yè)務(wù)邏輯解決數(shù)據(jù)傾斜往往更可靠扎狱。
- 減少job數(shù)
- 設(shè)置合理的mapTask、reduceTask數(shù)
- 對(duì)小文件進(jìn)行合并
- 優(yōu)化整體勃教,單一作業(yè)優(yōu)化不如整體優(yōu)化淤击。