打怪升级之小白的大数据之旅(六十九)<Hive旅程第十站:Hive的优化>
打怪升級(jí)之小白的大數(shù)據(jù)之旅(六十九)
Hive旅程第十站:Hive的優(yōu)化
上次回顧
上一章介紹了Hive的壓縮與存儲(chǔ)格式,本章節(jié)是Hive的一起其他優(yōu)化方法
Fetch抓取
-
Fetch抓取是指,Hive中對(duì)某些情況的查詢可以不必使用MapReduce計(jì)算
-
從hive學(xué)到了現(xiàn)在,大家有沒有這個(gè)疑問(wèn),為什么使用select * from 表名的時(shí)候,hive不走M(jìn)R程序呢?而使用select count(*) from 表名會(huì)執(zhí)行MR程序?
-
SELECT * FROM 表名;在這種情況下,Hive可以簡(jiǎn)單地讀取該表對(duì)應(yīng)的存儲(chǔ)目錄下的文件,然后輸出查詢結(jié)果到控制臺(tái)(因?yàn)楸硎峭ㄟ^(guò)元數(shù)據(jù)做映射的,實(shí)際表它就是一個(gè)文件夾)
-
在hive-default.xml.template文件中hive.fetch.task.conversion默認(rèn)是more,老版本hive默認(rèn)是minimal,該屬性修改為more以后,在全局查找、字段查找、limit查找等都不走mapreduce
以我們的emp員工表查詢舉例:
- 把hive.fetch.task.conversion設(shè)置成none,然后執(zhí)行查詢語(yǔ)句,都會(huì)執(zhí)行mapreduce程序# 設(shè)置抓取為none set hive.fetch.task.conversion=none; select *from emp; select ename from emp; select ename from emp limit 3;
- 把hive.fetch.task.conversion設(shè)置成more,然后執(zhí)行查詢語(yǔ)句,如下查詢方式都不會(huì)執(zhí)行mapreduce程序# 設(shè)置抓取為none set hive.fetch.task.conversion=none; select *from emp; select ename from emp; select ename from emp limit 3;
本地模式
- 在實(shí)際開發(fā)中,大多數(shù)的Hadoop Job是需要Hadoop提供的完整的可擴(kuò)展性來(lái)處理大數(shù)據(jù)集的
- 不過(guò),有時(shí)Hive的輸入數(shù)據(jù)量是非常小的。在這種情況下,為查詢觸發(fā)執(zhí)行任務(wù)消耗的時(shí)間可能會(huì)比實(shí)際job的執(zhí)行時(shí)間要多的多
- 對(duì)于大多數(shù)這種情況,Hive可以通過(guò)本地模式在單臺(tái)機(jī)器上處理所有的任務(wù)。對(duì)于小數(shù)據(jù)集,執(zhí)行時(shí)間可以明顯被縮短
- 我們可以通過(guò)設(shè)置hive.exec.mode.local.auto的值為true,來(lái)讓Hive在適當(dāng)?shù)臅r(shí)候自動(dòng)啟動(dòng)這個(gè)優(yōu)化
- 具體參數(shù)說(shuō)明如下:set hive.exec.mode.local.auto=true; //開啟本地mr //設(shè)置local mr的最大輸入數(shù)據(jù)量,當(dāng)輸入數(shù)據(jù)量小于這個(gè)值時(shí)采用local mr的方式,默認(rèn)為134217728,即128M set hive.exec.mode.local.auto.inputbytes.max=50000000; //設(shè)置local mr的最大輸入文件個(gè)數(shù),當(dāng)輸入文件個(gè)數(shù)小于這個(gè)值時(shí)采用local mr的方式,默認(rèn)為4 set hive.exec.mode.local.auto.input.files.max=10;
還是以員工表emp舉例:
開啟本地模式,并執(zhí)行查詢語(yǔ)句
set hive.exec.mode.local.auto=true; select * from emp cluster by deptno; -- 用時(shí):Time taken: 1.328 seconds, Fetched: 14 row(s)關(guān)閉本地模式,并執(zhí)行查詢語(yǔ)句
set hive.exec.mode.local.auto=false; select * from emp cluster by deptno; -- 用時(shí):Time taken: 20.09 seconds, Fetched: 14 row(s)表的優(yōu)化
小表與大表的Join
- 在以前我們寫SQL時(shí),通常有個(gè)習(xí)慣,就是小表放左邊,大表放后面,這是因?yàn)閷ey相對(duì)分散,并且數(shù)據(jù)量小的表放在join的左邊,這樣可以有效減少內(nèi)存溢出錯(cuò)誤發(fā)生的幾率
- 新版的hive已經(jīng)對(duì)小表JOIN大表和大表JOIN小表進(jìn)行了優(yōu)化。小表放在左邊和右邊已經(jīng)沒有明顯區(qū)別
- 具體的優(yōu)化是因?yàn)橄旅孢@個(gè)配置參數(shù),默認(rèn)是true,如果我們?cè)O(shè)置為false,那么我們將小表放左邊和放右邊,效率就會(huì)有明顯的不同set hive.auto.convert.join = true;
大表與大表的Join
空Key過(guò)濾
實(shí)際開發(fā)過(guò)程中,數(shù)據(jù)集并不是都是有數(shù)據(jù)的,常常會(huì)遇到NULL字段,但是根據(jù)業(yè)務(wù)不同,我們?cè)诖蟊黹g的合并時(shí),對(duì)NULL的處理也有所不同,根據(jù)業(yè)務(wù)不同可以分為下面兩種情況
- 不需要字段為Null
- 此時(shí)我們可以先過(guò)濾Null然后再進(jìn)行Join,這樣還可以避免笛卡爾積的發(fā)生
- 非 inner join(因?yàn)閕nner join 默認(rèn)會(huì)獲取非Null數(shù)據(jù))
- 此時(shí)我們先Join再過(guò)濾Null
案例(測(cè)試數(shù)據(jù)可以后臺(tái)聯(lián)系我)
- 有時(shí)join超時(shí)是因?yàn)槟承﹌ey對(duì)應(yīng)的數(shù)據(jù)太多,而相同key對(duì)應(yīng)的數(shù)據(jù)都會(huì)發(fā)送到相同的reducer上,從而導(dǎo)致內(nèi)存不夠
- 此時(shí)我們應(yīng)該仔細(xì)分析這些異常的key,很多情況下,這些key對(duì)應(yīng)的數(shù)據(jù)是異常數(shù)據(jù)
- 我們需要在SQL語(yǔ)句中進(jìn)行過(guò)濾。例如key對(duì)應(yīng)的字段為空
進(jìn)行示例前,我們先開啟歷史服務(wù)器,便于我們觀察
-
配置mapred-site.xml
# 配置歷史服務(wù)器 <property> <name>mapreduce.jobhistory.address</name> <value>hadoop102:10020</value> </property> <property><name>mapreduce.jobhistory.webapp.address</name><value>hadoop102:19888</value> </property> -
啟動(dòng)歷史服務(wù)器
sbin/mr-jobhistory-daemon.sh start historyserver -
查看jobhistory
http://hadoop102:19888/jobhistory
測(cè)試數(shù)據(jù)(這個(gè)數(shù)據(jù)是很久之前模擬用戶使用搜索引擎時(shí)的記錄)
# 總共大概100萬(wàn)條,我只展示一部分 vim /opt/module/hive/dbdata/nullid\N 20111230000005 57375476989eea12893c0c3811607bcf 奇藝高清 1 1 http://www.qiyi.com/ \N 20111230000005 66c5bb7774e31d0a22278249b26bc83a 凡人修仙傳 3 1 http://www.booksky.org/BookDetail.aspx?BookID=1050804&Level=1 \N 20111230000007 b97920521c78de70ac38e3713f524b50 本本聯(lián)盟 1 1 http://www.bblianmeng.com/ \N 20111230000008 6961d0c97fe93701fc9c0d861d096cd9 華南師范大學(xué)圖書館 1 1 http://lib.scnu.edu.cn/ \N 20111230000008 f2f5a21c764aebde1e8afcc2871e086f 在線代理 2 1 http://proxyie.cn/ \N 20111230000009 96994a0480e7e1edcaef67b20d8816b7 偉大導(dǎo)演 1 1 http://movie.douban.com/review/1128960/ \N 20111230000009 698956eb07815439fe5f46e9a4503997 youku 1 1 http://www.youku.com/ \N 20111230000009 599cd26984f72ee68b2b6ebefccf6aed 安徽合肥365房產(chǎn)網(wǎng) 1 1 http://hf.house365.com/ \N 20111230000010 f577230df7b6c532837cd16ab731f874 哈薩克網(wǎng)址大全 1 1 http://www.kz321.com/ \N 20111230000010 285f88780dd0659f5fc8acc7cc4949f2 IQ數(shù)碼 1 1 http://www.iqshuma.com/ \N 20111230000010 f4ba3f337efb1cc469fcd0b34feff9fb 推薦待機(jī)時(shí)間長(zhǎng)的手機(jī) 1 1 http://mobile.zol.com.cn/148/1487938.html-
創(chuàng)建空id表
// 創(chuàng)建空id表 create table nullidtable(id bigint, t bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t'; -
加載空id數(shù)據(jù)到空id表中
- 測(cè)試不過(guò)濾空id
- 測(cè)試過(guò)濾空id
空key轉(zhuǎn)換
- 有時(shí)雖然某個(gè)key為空對(duì)應(yīng)的數(shù)據(jù)很多,但是相應(yīng)的數(shù)據(jù)不是異常數(shù)據(jù),必須要包含在join的結(jié)果中
- 此時(shí)我們可以表a中key為空的字段賦一個(gè)隨機(jī)的值,使得數(shù)據(jù)隨機(jī)均勻地分布到不同的reducer上
不隨機(jī)分布空null值
-- 設(shè)置5個(gè)reduce個(gè)數(shù) set mapreduce.job.reduces = 5; -- JOIN兩張表 insert overwrite table jointable select n.* from nullidtable n left join bigtable b on n.id = b.id;通過(guò)歷史服務(wù)器,我們可以發(fā)現(xiàn)出現(xiàn)了數(shù)據(jù)傾斜,第一條的執(zhí)行時(shí)間要遠(yuǎn)遠(yuǎn)大于其他
使用隨機(jī)分布空null值
下圖可以發(fā)現(xiàn),我們剛才的數(shù)據(jù)傾斜基本上得到了控制(數(shù)據(jù)傾斜不可能完全消除)
Group By
默認(rèn)情況下,Map階段同一Key數(shù)據(jù)分發(fā)給一個(gè)reduce,當(dāng)一個(gè)key數(shù)據(jù)過(guò)大時(shí)就傾斜了,如下圖
并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進(jìn)行部分聚合,最后在Reduce端得出最終結(jié)果
我們可以通過(guò)開啟Map端聚合來(lái)減少負(fù)載均衡
(1)是否在Map端進(jìn)行聚合,默認(rèn)為True set hive.map.aggr = true (2)在Map端進(jìn)行聚合操作的條目數(shù)目 set hive.groupby.mapaggr.checkinterval = 100000 (3)有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(fù)載均衡(默認(rèn)是false) set hive.groupby.skewindata = true開啟Map端聚合來(lái)減少負(fù)載均衡原理:
- 當(dāng)選項(xiàng)設(shè)定為 true,生成的查詢計(jì)劃會(huì)有兩個(gè)MR Job
- 第一個(gè)MR Job中,Map的輸出結(jié)果會(huì)隨機(jī)分布到Reduce中,每個(gè)Reduce做部分聚合操作,并輸出結(jié)果
- 這樣處理的結(jié)果是相同的Group By Key有可能被分發(fā)到不同的Reduce中,從而達(dá)到負(fù)載均衡的目的;
- 第二個(gè)MR Job再根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照Group By Key分布到Reduce中(這個(gè)過(guò)程可以保證相同的Group By Key被分布到同一個(gè)Reduce中),最后完成最終的聚合操作
Count(Distinct) 去重統(tǒng)計(jì)
- 數(shù)據(jù)量小的時(shí)候無(wú)所謂,數(shù)據(jù)量大的情況下,由于COUNT DISTINCT操作需要用一個(gè)Reduce Task來(lái)完成
- 這一個(gè)Reduce需要處理的數(shù)據(jù)量太大,就會(huì)導(dǎo)致整個(gè)Job很難完成
- 一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換,但是需要注意group by造成的數(shù)據(jù)傾斜問(wèn)題
笛卡爾積
笛卡爾積在Hadoop介紹過(guò)了,我們盡量避免笛卡爾積,join的時(shí)候不加on條件,或者無(wú)效的on條件,Hive只能使用1個(gè)reducer來(lái)完成笛卡爾積
行列過(guò)濾
- 列處理:在SELECT中,只拿需要的列,如果有,盡量使用分區(qū)過(guò)濾,少用SELECT *。
- 行處理:在分區(qū)剪裁中,當(dāng)使用外關(guān)聯(lián)時(shí),如果將副表的過(guò)濾條件寫在Where后面,那么就會(huì)先全表關(guān)聯(lián),之后再過(guò)濾
- 在HQL中,當(dāng)我們使用了where,底層會(huì)優(yōu)先執(zhí)行過(guò)濾條件,通常稱這個(gè)操作為謂詞下推
- 意思就是當(dāng)sql語(yǔ)句不是很長(zhǎng)的時(shí)候,它會(huì)將HQL語(yǔ)句中的where過(guò)濾條件先執(zhí)行再進(jìn)行關(guān)聯(lián)操作,第二種相當(dāng)于手動(dòng)進(jìn)行謂詞下推操作,子查詢進(jìn)行了過(guò)濾之后,在進(jìn)行聯(lián)表操作
分區(qū)和分桶
使用了分區(qū)表和分桶表可以大大提高我們的查詢效率,具體的創(chuàng)建和使用方法我在單獨(dú)的那一章介紹過(guò)了:https://blog.csdn.net/Li_G_yuan/article/details/117395941?spm=1001.2014.3001.5501
并行執(zhí)行&JVM重用
JVM重用
- JVM重用我在Hadoop優(yōu)化也講過(guò)了,就不再重復(fù)了
并行執(zhí)行 - 默認(rèn)情況下,Hive一次只會(huì)執(zhí)行一個(gè)階段
- 不過(guò),某個(gè)特定的job可能包含眾多的階段,而這些階段可能并非完全互相依賴的,也就是說(shuō)有些階段是可以并行執(zhí)行的
- 這樣可能使得整個(gè)job的執(zhí)行時(shí)間縮短。不過(guò),如果有更多的階段可以并行執(zhí)行,那么job可能就越快完成
- 在hive中,通過(guò)設(shè)置參數(shù)hive.exec.parallel值為true,就可以開啟并發(fā)執(zhí)行。不過(guò),在共享集群中,需要注意下,如果job中并行階段增多,那么集群利用率就會(huì)增加
當(dāng)然,得是在系統(tǒng)資源比較空閑的時(shí)候才有優(yōu)勢(shì),否則,沒資源,并行也起不來(lái)
嚴(yán)格模式
分區(qū)表不使用分區(qū)過(guò)濾
- 將hive.strict.checks.no.partition.filter設(shè)置為true時(shí),對(duì)于分區(qū)表,除非where語(yǔ)句中含有分區(qū)字段過(guò)濾條件來(lái)限制范圍,否則不允許執(zhí)行。
- 換句話說(shuō),就是用戶不允許掃描所有分區(qū)。進(jìn)行這個(gè)限制的原因是,通常分區(qū)表都擁有非常大的數(shù)據(jù)集,而且數(shù)據(jù)增加迅速。
- 沒有進(jìn)行分區(qū)限制的查詢可能會(huì)消耗令人不可接受的巨大資源來(lái)處理這個(gè)表
使用order by沒有l(wèi)imit過(guò)濾
- 將hive.strict.checks.orderby.no.limit設(shè)置為true時(shí),對(duì)于使用了order by語(yǔ)句的查詢,要求必須使用limit語(yǔ)
- 因?yàn)閛rder by為了執(zhí)行排序過(guò)程會(huì)將所有的結(jié)果數(shù)據(jù)分發(fā)到同一個(gè)Reducer中進(jìn)行處理
- 強(qiáng)制要求用戶增加這個(gè)LIMIT語(yǔ)句可以防止Reducer額外執(zhí)行很長(zhǎng)一段時(shí)間
笛卡爾積判定
- 將hive.strict.checks.cartesian.product設(shè)置為true時(shí),會(huì)限制笛卡爾積的查詢。hive.strict.checks.cartesian.product
執(zhí)行計(jì)劃
實(shí)際開發(fā)中,我們要善用執(zhí)行計(jì)劃來(lái)查看我們的HQL語(yǔ)句,這樣可以大大減少因?yàn)檎Z(yǔ)法問(wèn)題導(dǎo)致時(shí)間的浪費(fèi)
語(yǔ)法格式
EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query (1)查看下面這條語(yǔ)句的執(zhí)行計(jì)劃 hive (default)> explain select * from emp; hive (default)> explain select deptno, avg(sal) avg_sal from emp group by deptno; (2)查看詳細(xì)執(zhí)行計(jì)劃 hive (default)> explain extended select * from emp; hive (default)> explain extended select deptno, avg(sal) avg_sal from emp group by deptno;總結(jié)
Hive的所有知識(shí)點(diǎn)到這里就結(jié)束了,下一章是一綜合案例,綜合案例完畢我會(huì)總結(jié)一下整個(gè)Hive的內(nèi)容
總結(jié)
以上是生活随笔為你收集整理的打怪升级之小白的大数据之旅(六十九)<Hive旅程第十站:Hive的优化>的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 大学生的移动开发之惑
- 下一篇: 解决react antd design