版權(quán)聲明:本文為博主原創(chuàng)文章图焰,未經(jīng)博主允許不得轉(zhuǎn)載 https://blog.csdn.net/yu0_zhang0/article/details/81776459
概述
Hive學習也有一段時間了寻咒,今天來對Hive進行一個總結(jié)财喳,談談自己的理解,作者還是個小白揍庄,有不對的地方請大家指出相互學習脖旱,共同進步。今天來談一談什么是Hive尉尾,產(chǎn)生背景爆阶,優(yōu)勢等一系列問題。
什么是Hive
老規(guī)矩:官網(wǎng)地址
Hive wiki.
先來談談自己的理解:
有些人可能會說Hive不就是寫SQL的嗎沙咏,那我們其實可以從另一個角度來理解:Hive就是那么強大啊辨图,只要寫SQL就能解決問題,其實這些人說的也沒錯Hive確實就是寫SQL的肢藐,對于傳統(tǒng)的 DBA人員或者會寫SQL就很容易上手了故河,但是您知道他的底層細節(jié)嗎,怎么優(yōu)化呢吆豹?和傳統(tǒng)的關(guān)系型數(shù)據(jù)庫又有什么區(qū)別呢鱼的?等等一系列問題。痘煤。凑阶。
Hive是一個構(gòu)建在Hadoop之上的數(shù)據(jù)倉庫軟件,它可以使已經(jīng)存儲的數(shù)據(jù)結(jié)構(gòu)化,它提供類似sql的查詢語句HiveQL對數(shù)據(jù)進行分析處理衷快。 Hive將HiveQL語句轉(zhuǎn)換成一系列成MapReduce作業(yè)并執(zhí)行(SQL轉(zhuǎn)化為MapReduce的過程你知道嗎宙橱?)。用戶可以很方便的使用命令行和JDBC程序的方式來連接到hive烦磁。 目前养匈,Hive除了支持MapReduce計算引擎,還支持Spark和Tez這兩中分布式計算引擎都伪。常用于離線批處理呕乎。 (Hive On Spark 還是試驗版本)
Hive的產(chǎn)生背景
大數(shù)據(jù)的時代,海量的數(shù)據(jù)對于傳統(tǒng)的關(guān)系型數(shù)據(jù)庫來說維護起來成本非常高陨晶,那該如何是好猬仁,Hadoop分布式的框架帝璧,可以使用廉價的機器部署分布式系統(tǒng)把數(shù)據(jù)存儲再HDFS之上,通過MR進行計算湿刽,分析的烁,這樣是可以的,但是诈闺,MR大家應該知道渴庆,MapReduce編程帶來的不便性,編程十分繁瑣雅镊,在大多情況下襟雷,每個MapReduce程序需要包含Mapper、Reduceer和一個Driver仁烹,之后需要打成jar包扔到集群上運 行耸弄。如果mr寫完之后,且該項目已經(jīng)上線卓缰,一旦業(yè)務邏輯發(fā)生了改變计呈,可能就會帶來大規(guī)模的改動代碼,然后重新打包征唬,發(fā)布捌显,非常麻煩(這種方式,也是最古老的方式)
當大量數(shù)據(jù)都存放在HDFS上鳍鸵,如何快速的對HDFS上的文件進行統(tǒng)計分析操作苇瓣?
一般來說,想要做會有兩種方式:
學Java偿乖、學MapReduce(十分麻煩)
做DBA的:寫SQL(希望能通過寫SQL這樣的方式來實現(xiàn),這種方式較好)
然而哲嘲,HDFS中最關(guān)鍵的一點就是贪薪,數(shù)據(jù)存儲HDFS上是沒有schema的概念的(schema:相當于表里面有列、字段眠副、字段名稱画切、字段與字段之間的分隔符等,這些就是schema信息)然而HDFS上的僅僅只是一個純的文本文件而已囱怕,那么霍弹,沒有schema,就沒辦法使用sql進行查詢了啊娃弓。典格。。因此台丛,在這種背景下耍缴,就有問題產(chǎn)生:如何為HDFS上的文件添加Schema信息?如果加上去,是否就可以通過SQL的方式進行處理了呢防嗡?于是強大的Hive出現(xiàn)了变汪。
Hive深入剖析
再來看看官網(wǎng)給我們的介紹:
官方第一句話就說明了Apache Hive 是構(gòu)建在Apache Hadoop之上的數(shù)據(jù)倉庫。有助于對大型的數(shù)據(jù)集進行讀蚁趁、寫和管理裙盾。
那我們先對這句話進行剖析:
首先Hive是構(gòu)建在Hadoop之上的,其實就是Hive中的數(shù)據(jù)其實是存儲再HDFS上的(加上LOCAL關(guān)鍵字則是在本地)他嫡,默認在/user/hive/warehouse/table,有助于對大型數(shù)據(jù)集進行讀番官、寫和管理,那也就是意味著傳統(tǒng)的關(guān)系型數(shù)據(jù)庫已經(jīng)無法滿足現(xiàn)在的數(shù)據(jù)量了涮瞻,需要一個更大的倉庫來幫助我們存儲鲤拿,這里也引出一個問題:Hive和關(guān)系型數(shù)據(jù)庫的區(qū)別,后面我們再來聊署咽。
Hive的特征:
1.可通過SQL輕松訪問數(shù)據(jù)的工具近顷,從而實現(xiàn)數(shù)據(jù)倉庫任務,如提取/轉(zhuǎn)換/加載(ETL)宁否,報告和數(shù)據(jù)分析窒升。
2.它可以使已經(jīng)存儲的數(shù)據(jù)結(jié)構(gòu)化
3.可以直接訪問存儲在Apache HDFS?或其他數(shù)據(jù)存儲系統(tǒng)(如Apache HBase?)中的文件
4.Hive除了支持MapReduce計算引擎,還支持Spark和Tez這兩中分布式計算引擎(這里會引申出一個問題慕匠,哪些查詢跑mr哪些不跑饱须?)
5.它提供類似sql的查詢語句HiveQL對數(shù)據(jù)進行分析處理。
- 數(shù)據(jù)的存儲格式有多種台谊,比如數(shù)據(jù)源是二進制格式蓉媳, 普通文本格式等等
而hive強大之處不要求數(shù)據(jù)轉(zhuǎn)換成特定的格式,而是利用hadoop本身InputFormat API來從不同的數(shù)據(jù)源讀取數(shù)據(jù)锅铅,同樣地使用OutputFormat API將數(shù)據(jù)寫成不同的格式酪呻。所以對于不同的數(shù)據(jù)源,或者寫出不同的格式就需要不同的對應的InputFormat和Outputformat類的實現(xiàn)盐须。
以stored as textfile為例玩荠,其在底層java API中表現(xiàn)是輸入InputFormat格式:TextInputFormat以及輸出OutputFormat格式:HiveIgnoreKeyTextOutputFormat.這里InputFormat中定義了如何對數(shù)據(jù)源文本進行讀取劃分,以及如何將切片分割成記錄存入表中贼邓。而Outputformat定義了如何將這些切片寫回到文件里或者直接在控制臺輸出阶冈。
不僅如此Hive的SQL還可以通過用戶定義的函數(shù)(UDF),用戶定義的聚合(UDAF)和用戶定義的表函數(shù)(UDTF)進行擴展塑径。
(幾個函數(shù)之間的區(qū)別)
Hive中不僅可以使用逗號和制表符分隔值(CSV / TSV)文本文件女坑,還可以使用Sequence File、RC晓勇、ORC堂飞、Parquet
(知道這幾種存儲格式的區(qū)別)灌旧,
當然Hive還可以通過用戶來自定義自己的存儲格式,基本上前面說的到的幾種格式完全夠了绰筛。
Hive旨在最大限度地提高可伸縮性(通過向Hadoop集群動態(tài)添加更多機器擴展)枢泰,性能,可擴展性铝噩,
容錯性以及與其輸入格式的松散耦合衡蚂。
1
2
3
4
5
6
7
安裝部署
安裝部署這里我們就不講解了,不會的同學骏庸,參考作者以前的博客
Hive基本語法
改篇博客主要講解Hive底層的東西和一些優(yōu)化對于基本的東西可以參考作者以前的博客毛甲。
DDL
DML
基本SQL
內(nèi)置函數(shù)和基本的UDF函數(shù)
UDF函數(shù)這里要進行一個講解UDF、DUAF具被、UDTF分別是啥玻募。
我們知道Hive的SQL還可以通過用戶定義的函數(shù)(UDF),用戶定義的聚合(UDAF)和用戶定義的表函數(shù)(UDTF)進行擴展一姿。
當Hive提供的內(nèi)置函數(shù)無法滿足你的業(yè)務處理需要時七咧,此時就可以考慮使用用戶自定義函數(shù)(UDF:user-defined function)《L荆
UDF(User-Defined-Function) 一進一出
UDAF(User- Defined Aggregation Funcation) 聚集函數(shù)艾栋,多進一出。
UDTF(User-Defined Table-Generating Functions) 一進多出蛉顽,如lateral view explore()
Hive于關(guān)系型數(shù)據(jù)庫的區(qū)別
時效性蝗砾、延時性比較高,可擴展性高携冤;
Hive數(shù)據(jù)規(guī)模大悼粮,優(yōu)勢在于處理大數(shù)據(jù)集,對于小數(shù)據(jù)集沒有優(yōu)勢
事務沒什么用(比較雞肋曾棕,沒什么實際的意義矮锈,對于離線的來說) 一個小問題:那個版本開始提供了事務?
insert/update沒什么實際用途睁蕾,大數(shù)據(jù)場景下大多數(shù)是select
RDBMS也支持分布式,節(jié)點有限 成本高债朵,處理的數(shù)據(jù)量小
Hadoop集群規(guī)模更大 部署在廉價機器上子眶,處理的數(shù)據(jù)量大
數(shù)據(jù)庫可以用在Online的應用中,Hive主要進行離線的大數(shù)據(jù)分析序芦;
數(shù)據(jù)庫的查詢語句為SQL臭杰,Hive的查詢語句為HQL;
數(shù)據(jù)庫數(shù)據(jù)存儲在LocalFS谚中,Hive的數(shù)據(jù)存儲在HDFS渴杆;
數(shù)據(jù)格式:Hive中有多種存儲格式:由于在加載數(shù)據(jù)的過程中寥枝,不需要從用戶數(shù)據(jù)格式到 Hive 定義的數(shù)據(jù)格式的轉(zhuǎn)換,
因此磁奖,Hive 在加載的過程中不會對數(shù)據(jù)本身進行任何修改囊拜,而只是將數(shù)據(jù)內(nèi)容復制或者移動到相應的 HDFS 目錄中。
而在數(shù)據(jù)庫中比搭,不同的數(shù)據(jù)庫有不同的存儲引擎冠跷,定義了自己的數(shù)據(jù)格式。所有數(shù)據(jù)都會按照一定的組織存儲身诺,因此蜜托,
數(shù)據(jù)庫加載數(shù)據(jù)的過程會比較耗時。
Hive執(zhí)行MapReduce霉赡,MySQL執(zhí)行Executor橄务;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Hive的優(yōu)點
1.簡單易上手
2.擴展能力較好(指集群 HDFS或是YARN)
3.統(tǒng)一的元數(shù)據(jù)管理 metastore包括的了數(shù)據(jù)庫,表穴亏,字段分區(qū)等詳細信息
1
2
3
該篇博客對于元數(shù)據(jù)信息進行了詳細的講解
4.由于統(tǒng)一的元數(shù)據(jù)管理所以和spark/impala等SQL引擎是通用的
通用是指蜂挪,在擁有了統(tǒng)一的metastore之后,在Hive中創(chuàng)建一張表迫肖,在Spark/impala中是能用的锅劝,反之在Spark中創(chuàng)建一張表,
在Hive中也能用蟆湖;只需要共用元數(shù)據(jù)故爵,就可以切換SQL引擎
涉及到了Spark sql 和Hive On Spark(實驗版本)
5.使用SQL語法,提供快速開發(fā)的能力隅津,支持自定義函數(shù)UDF诬垂。
6.避免了去寫mapreduce,減少開發(fā)人員學習成本伦仍。
7.數(shù)據(jù)離線處理结窘,比如日志分析,海量數(shù)據(jù)結(jié)構(gòu)化分析
1
2
3
4
5
6
7
SQL轉(zhuǎn)化為MapReduce的過程
了解了MapReduce實現(xiàn)SQL基本操作之后充蓝,我們來看看Hive是如何將SQL轉(zhuǎn)化為MapReduce任務的隧枫,整個編譯過程分為六個階段:
Antlr定義SQL的語法規(guī)則,完成SQL詞法谓苟,語法解析官脓,將SQL轉(zhuǎn)化為抽象語法樹AST Tree
遍歷AST Tree,抽象出查詢的基本組成單元QueryBlock
遍歷QueryBlock涝焙,翻譯為執(zhí)行操作樹OperatorTree
邏輯層優(yōu)化器進行OperatorTree變換卑笨,合并不必要的ReduceSinkOperator,減少shuffle數(shù)據(jù)量
遍歷OperatorTree仑撞,翻譯為MapReduce任務
物理層優(yōu)化器進行MapReduce任務的變換赤兴,生成最終的執(zhí)行計劃
可以參考美團的技術(shù)沙龍
Hive內(nèi)部表和外部表的區(qū)別
未被external修飾的是內(nèi)部表(managed table)妖滔,被external修飾的為外部表(external table);
**區(qū)別: **
內(nèi)部表數(shù)據(jù)由Hive自身管理桶良,外部表數(shù)據(jù)由HDFS管理座舍;
內(nèi)部表數(shù)據(jù)存儲的位置是hive.metastore.warehouse.dir(默認:/user/hive/warehouse),外部表數(shù)據(jù)的存儲位置由自己制定艺普;
刪除內(nèi)部表會直接刪除元數(shù)據(jù)(metadata)及存儲數(shù)據(jù)簸州;刪除外部表僅僅會刪除元數(shù)據(jù),HDFS上的文件并不會被刪除歧譬;
行式存儲vs列式存儲
行式數(shù)據(jù)庫存儲在hdfs上式按行進行存儲的岸浑,一個block存儲一或多行數(shù)據(jù)。而列式數(shù)據(jù)庫在hdfs上則是按照列進行存儲瑰步,一個block可能有一列或多列數(shù)據(jù)矢洲。
如果要將數(shù)據(jù)進行壓縮:
對于行式數(shù)據(jù)庫,必然按行壓縮缩焦,當一行中有多個字段读虏,各個字段對應的數(shù)據(jù)類型可能不一致,壓縮性能壓縮比就比較差袁滥。
對于列式數(shù)據(jù)庫盖桥,必然按列壓縮,每一列對應的是相同數(shù)據(jù)類型的數(shù)據(jù)题翻,故列式數(shù)據(jù)庫的壓縮性能要強于行式數(shù)據(jù)庫揩徊。
如果要進行數(shù)據(jù)的查詢:
假設(shè)執(zhí)行的查詢操作是:select id,name from table_emp;
對于行式數(shù)據(jù)庫,它要遍歷一整張表將每一行中的id,name字段拼接再展現(xiàn)出來嵌赠,這樣需要查詢的數(shù)據(jù)量就比較大塑荒,效率低。
對于列式數(shù)據(jù)庫姜挺,它只需找到對應的id,name字段的列展現(xiàn)出來即可齿税,需要查詢的數(shù)據(jù)量小,效率高炊豪。
假設(shè)執(zhí)行的查詢操作是:select * from table_emp;
對于這種查詢整個表全部信息的操作凌箕,由于列式數(shù)據(jù)庫需要將分散的行進行重新組合,行式數(shù)據(jù)庫效率就高于列式數(shù)據(jù)庫词渤。
但是陌知,在大數(shù)據(jù)領(lǐng)域,進行全表查詢的場景少之又少掖肋,進而我們使用較多的還是列式數(shù)據(jù)庫及列式儲存。
Hive哪些查詢會執(zhí)行mr
hive 0.10.0為了執(zhí)行效率考慮赏参,簡單的查詢志笼,就是只是select沿盅,不帶count,sum,group by這樣的,都不走map/reduce纫溃,直接讀取hdfs文件進行filter過濾腰涧。
這樣做的好處就是不新開mr任務,執(zhí)行效率要提高不少紊浩,但是不好的地方就是用戶界面不友好窖铡,有時候數(shù)據(jù)量大還是要等很長時間,但是又沒有任何返回坊谁。
改這個很簡單费彼,在hive-site.xml里面有個配置參數(shù)叫
hive.fetch.task.conversion
將這個參數(shù)設(shè)置為more汛骂,簡單查詢就不走map/reduce了橡庞,設(shè)置為minimal陶夜,就任何簡單select都會走map/reduce
Create Table As Select (CTAS) 走mr
create table emp2 as select * from emp;
1
2
insert一條或者多條 走mr
1
Hive靜態(tài)分區(qū)動態(tài)分區(qū)
分區(qū)的概念
Hive的分區(qū)方式:由于Hive實際是存儲在HDFS上的抽象儿子,Hive的一個分區(qū)名對應HDFS上的一個目錄名担敌,子分區(qū)名就是子目錄名跪者,并不是一個實際字段洛巢。
分區(qū)的好處
產(chǎn)生背景:如果一個表中數(shù)據(jù)很多坡贺,我們查詢時就很慢小染,耗費大量時間翘瓮,如果要查詢其中部分數(shù)據(jù)該怎么辦呢,這是我們引入分區(qū)的概念裤翩。
Partition:分區(qū)资盅,每張表中可以加入一個分區(qū)或者多個,方便查詢岛都,提高效率律姨;并且HDFS上會有對應的分區(qū)目錄:
語法:
Hive分區(qū)是在創(chuàng)建表的時候用Partitioned by 關(guān)鍵字定義的,但要注意臼疫,Partitioned by子句中定義的列是表中正式的列择份,
但是Hive下的數(shù)據(jù)文件中并不包含這些列,因為它們是目錄名烫堤,真正的數(shù)據(jù)在分區(qū)目錄下荣赶。
靜態(tài)分區(qū)和 動態(tài)分區(qū)的區(qū)別
創(chuàng)建表的語法都一樣
靜態(tài)分區(qū):加載數(shù)據(jù)的時候要指定分區(qū)的值(key=value),比較麻煩的是每次插入數(shù)據(jù)都要指定分區(qū)的值鸽斟,創(chuàng)建多個分區(qū)多分區(qū)一樣拔创,以逗號分隔。
動態(tài)分區(qū):
如果用上述的靜態(tài)分區(qū)富蓄,插入的時候必須首先要知道有什么分區(qū)類型剩燥,而且每個分區(qū)寫一個load data,太煩人。使用動態(tài)分區(qū)可解決以上問題灭红,其可以根據(jù)查詢得到的數(shù)據(jù)動態(tài)分配到分區(qū)里侣滩。其實動態(tài)分區(qū)與靜態(tài)分區(qū)區(qū)別就是不指定分區(qū)目錄,由系統(tǒng)自己選擇变擒。
首先君珠,啟動動態(tài)分區(qū)功能
hive> set hive.exec.dynamic.partition=true;
采用動態(tài)方式加載數(shù)據(jù)到目標表
加載之前先設(shè)置一下下面的參數(shù)
hive (default)> set hive.exec.dynamic.partition.mode=nonstrict
1
開始加載
insert into table emp_dynamic_partition partition(deptno)
select empno , ename , job , mgr , hiredate , sal , comm, deptno from emp;
1
2
3
4
5
6
7
8
9
10
11
12
13
加載數(shù)據(jù)方式并沒有指定具體的分區(qū),只是指出了分區(qū)字段娇斑。
在select最后一個字段必須跟你的分區(qū)字段策添,這樣就會自行根據(jù)deptno的value來分區(qū)。
刪除分區(qū):
ALTER TABLE my_partition_test_table DROP IF EXISTS PARTITION (day='2018-08-08');
Hive優(yōu)化
1.我們知道大數(shù)據(jù)場景下不害怕數(shù)據(jù)量大毫缆,害怕的是數(shù)據(jù)傾斜唯竹,怎樣避免數(shù)據(jù)傾斜,找到可能產(chǎn)生數(shù)據(jù)傾斜的函數(shù)尤為關(guān)鍵悔醋,數(shù)據(jù)量較大的情況下摩窃,慎用count(distinct),count(distinct)容易產(chǎn)生傾斜問題芬骄。
2.設(shè)置合理的map reduce 的task數(shù)量
map階段優(yōu)化
mapred.min.split.size: 指的是數(shù)據(jù)的最小分割單元大谢浮;min的默認值是1B
mapred.max.split.size: 指的是數(shù)據(jù)的最大分割單元大姓俗琛蒂秘;max的默認值是256MB
通過調(diào)整max可以起到調(diào)整map數(shù)的作用,減小max可以增加map數(shù)淘太,增大max可以減少map數(shù)姻僧。
需要提醒的是,直接調(diào)整mapred.map.tasks這個參數(shù)是沒有效果的蒲牧。
1
2
3
4
舉例:
a) 假設(shè)input目錄下有1個文件a,大小為780M,那么hadoop會將該文件a分隔成7個塊(6個128m的塊和1個12m的塊)撇贺,從而產(chǎn)生7個map數(shù)
b) 假設(shè)input目錄下有3個文件a,b,c,大小分別為10m,20m冰抢,130m松嘶,那么hadoop會分隔成4個塊(10m,20m,128m,2m),從而產(chǎn)生4個map數(shù)
即,如果文件大于塊大小(128m),那么會拆分挎扰,如果小于塊大小翠订,則把該文件當成一個塊。
其實這就涉及到小文件的問題:如果一個任務有很多小文件(遠遠小于塊大小128m),則每個小文件也會被當做一個塊遵倦,用一個map任務來完成尽超,
而一個map任務啟動和初始化的時間遠遠大于邏輯處理的時間,就會造成很大的資源浪費梧躺。
而且似谁,同時可執(zhí)行的map數(shù)是受限的。那么問題又來了。棘脐。是不是保證每個map處理接近128m的文件塊斜筐,就高枕無憂了?
答案也是不一定蛀缝。比如有一個127m的文件,正常會用一個map去完成目代,但這個文件只有一個或者兩個小字段屈梁,卻有幾千萬的記錄,
如果map處理的邏輯比較復雜榛了,用一個map任務去做在讶,肯定也比較耗時。
我們該如何去解決呢霜大?构哺??
我們需要采取兩種方式來解決:即減少map數(shù)和增加map數(shù)战坤;
減少map數(shù)量
假設(shè)一個SQL任務:
Select count(1) from popt_tbaccountcopy_mes where pt = ‘2012-07-04’;
該任務的inputdir /group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04
共有194個文件曙强,其中很多是遠遠小于128m的小文件,總大小9G途茫,正常執(zhí)行會用194個map任務碟嘴。
Map總共消耗的計算資源: SLOTS_MILLIS_MAPS= 623,020
我通過以下方法來在map執(zhí)行前合并小文件,減少map數(shù):
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
再執(zhí)行上面的語句囊卜,用了74個map任務娜扇,map消耗的計算資源:SLOTS_MILLIS_MAPS= 333,500
對于這個簡單SQL任務,執(zhí)行時間上可能差不多栅组,但節(jié)省了一半的計算資源雀瓢。
大概解釋一下,100000000表示100M, set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;這個參數(shù)表示執(zhí)行前進行小文件合并玉掸,前面三個參數(shù)確定合并文件塊的大小刃麸,大于文件塊大小128m的,按照128m來分隔排截,小于128m,大于100m的嫌蚤,按照100m來分隔,把那些小于100m的(包括小文件和分隔大文件剩下的)断傲,進行合并,最終生成了74個塊脱吱。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
增大map數(shù)量
如何適當?shù)脑黾觤ap數(shù)?
當input的文件都很大认罩,任務邏輯復雜箱蝠,map執(zhí)行非常慢的時候,可以考慮增加Map數(shù),
來使得每個map處理的數(shù)據(jù)量減少宦搬,從而提高任務的執(zhí)行效率牙瓢。
假設(shè)有這樣一個任務:
Select data_desc,
count(1),
count(distinct id),
sum(case when …),
sum(case when ...),
sum(…)
from a group by data_desc
如果表a只有一個文件,大小為120M间校,但包含幾千萬的記錄矾克,如果用1個map去完成這個任務,
肯定是比較耗時的憔足,這種情況下胁附,我們要考慮將這一個文件合理的拆分成多個,
這樣就可以用多個map任務去完成滓彰。
set mapred.reduce.tasks=10;
create table a_1 as
select * from a
distribute by rand(123);
這樣會將a表的記錄控妻,隨機的分散到包含10個文件的a_1表中,再用a_1代替上面sql中的a表揭绑,
則會用10個map任務去完成弓候。
每個map任務處理大于12M(幾百萬記錄)的數(shù)據(jù),效率肯定會好很多他匪。
看上去菇存,貌似這兩種有些矛盾,一個是要合并小文件诚纸,一個是要把大文件拆成小文件撰筷,
這點正是重點需要關(guān)注的地方,
使單個map任務處理合適的數(shù)據(jù)量畦徘;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
reduce階段優(yōu)化
Reduce的個數(shù)對整個作業(yè)的運行性能有很大影響毕籽。如果Reduce設(shè)置的過大,那么將會產(chǎn)生很多小文件井辆,
對NameNode會產(chǎn)生一定的影響关筒,
而且整個作業(yè)的運行時間未必會減少;如果Reduce設(shè)置的過小杯缺,那么單個Reduce處理的數(shù)據(jù)將會加大蒸播,
很可能會引起OOM異常。
如果設(shè)置了mapred.reduce.tasks/mapreduce.job.reduces參數(shù)萍肆,那么Hive會直接使用它的值作為Reduce的個數(shù)袍榆;
如果mapred.reduce.tasks/mapreduce.job.reduces的值沒有設(shè)置(也就是-1),那么Hive會
根據(jù)輸入文件的大小估算出Reduce的個數(shù)塘揣。
根據(jù)輸入文件估算Reduce的個數(shù)可能未必很準確包雀,因為Reduce的輸入是Map的輸出,而Map的輸出可能會比輸入要小亲铡,
所以最準確的數(shù)根據(jù)Map的輸出估算Reduce的個數(shù)才写。
1
2
3
4
5
6
7
8
9
Hive自己如何確定reduce數(shù):
reduce個數(shù)的設(shè)定極大影響任務執(zhí)行效率葡兑,不指定reduce個數(shù)的情況下,Hive會猜測確定一個reduce個數(shù)赞草,基于以下兩個設(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
1
2
3
4
調(diào)整reduce個數(shù)方法一:
調(diào)整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
1
2
3
調(diào)整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
1
2
reduce個數(shù)并不是越多越好搭独;
同map一樣,啟動和初始化reduce也會消耗時間和資源廊镜;
另外牙肝,有多少個reduce,就會有多少個輸出文件,如果生成了很多個小文件嗤朴,那么如果這些小文件作為下一個任務的輸入配椭,
則也會出現(xiàn)小文件過多的問題;
1
2
3
什么情況下只有一個reduce雹姊;
很多時候你會發(fā)現(xiàn)任務中不管數(shù)據(jù)量多大股缸,不管你有沒有設(shè)置調(diào)整reduce個數(shù)的參數(shù),任務中一直都只有一個reduce任務吱雏;
其實只有一個reduce任務的情況敦姻,除了數(shù)據(jù)量小于hive.exec.reducers.bytes.per.reducer參數(shù)值的情況外,還有以下原因:
沒有g(shù)roup 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’;
這點非常常見镰惦,希望大家盡量改寫。
用了Order by
有笛卡爾積
通常這些情況下犬绒,除了找辦法來變通和避免旺入,我暫時沒有什么好的辦法,因為這些操作都是全局的凯力,所以hadoop不得不用一個reduce去完成茵瘾;
同樣的,在設(shè)置reduce個數(shù)的時候也需要考慮這兩個原則:使大數(shù)據(jù)量利用合適的reduce數(shù)咐鹤;使單個reduce任務處理合適的數(shù)據(jù)量拗秘;
合并小文件
我們知道文件數(shù)目小,容易在文件存儲端造成瓶頸慷暂,給 HDFS 帶來壓力聘殖,影響處理效率晨雳。
對此,可以通過合并Map和Reduce的結(jié)果文件來消除這樣的影響奸腺。
用于設(shè)置合并屬性的參數(shù)有:
是否合并Map輸出文件:hive.merge.mapfiles=true(默認值為真)
是否合并Reduce 端輸出文件:hive.merge.mapredfiles=false(默認值為假)
合并文件的大胁徒:hive.merge.size.per.task=25610001000(默認值為 256000000)
1
2
3
4
5
6
Hive優(yōu)化之小文件問題及其解決方案
小文件是如何產(chǎn)生的
1.動態(tài)分區(qū)插入數(shù)據(jù),產(chǎn)生大量的小文件突照,從而導致map數(shù)量劇增帮非。
2.reduce數(shù)量越多,小文件也越多(reduce的個數(shù)和輸出文件是對應的)讹蘑。
3.數(shù)據(jù)源本身就包含大量的小文件末盔。
小文件問題的影響
1.從Hive的角度看,小文件會開很多map座慰,一個map開一個JVM去執(zhí)行陨舱,所以這些任務的初始化,啟動版仔,執(zhí)行會浪費大量的資源游盲,嚴重影響性能。
2.在HDFS中蛮粮,每個小文件對象約占150byte益缎,如果小文件過多會占用大量內(nèi)存。這樣NameNode內(nèi)存容量嚴重制約了集群的擴展然想。
小文件問題的解決方案
從小文件產(chǎn)生的途經(jīng)就可以從源頭上控制小文件數(shù)量莺奔,方法如下:
1.使用Sequencefile作為表存儲格式,不要用textfile变泄,在一定程度上可以減少小文件令哟。
2.減少reduce的數(shù)量(可以使用參數(shù)進行控制)。
3.少用動態(tài)分區(qū)杖刷,用時記得按distribute by分區(qū)励饵。
1
2
3
4
5
對于已有的小文件,我們可以通過以下幾種方案解決:
1.使用hadoop archive命令把小文件進行歸檔滑燃。
2.重建表役听,建表時減少reduce數(shù)量。
3.通過參數(shù)進行調(diào)節(jié)表窘,設(shè)置map/reduce端的相關(guān)參數(shù)典予,如下:
1
2
3
4
5
設(shè)置map輸入合并小文件的相關(guān)參數(shù):
[java] view plain copy
//每個Map最大輸入大小(這個值決定了合并后文件的數(shù)量)
set mapred.max.split.size=256000000;
//一個節(jié)點上split的至少的大小(這個值決定了多個DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一個交換機下split的至少的大小(這個值決定了多個交換機上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//執(zhí)行Map前進行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
設(shè)置map輸出和reduce輸出進行合并的相關(guān)參數(shù):
[java] view plain copy
//設(shè)置map端輸出進行合并,默認為true
set hive.merge.mapfiles = true
//設(shè)置reduce端輸出進行合并乐严,默認為false
set hive.merge.mapredfiles = true
//設(shè)置合并文件的大小
set hive.merge.size.per.task = 25610001000
//當輸出文件的平均大小小于該值時瘤袖,啟動一個獨立的MapReduce任務進行文件merge。
set hive.merge.smallfiles.avgsize=16000000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3.Write good SQL : 說道sql優(yōu)化很慚愧昂验,自己sql很爛捂敌,不多比比了艾扮,但是sql優(yōu)化確實很關(guān)鍵。占婉。泡嘴。
4.存儲格式:可以使用列裁剪,分區(qū)裁剪逆济,orc酌予,parquet等存儲格式。參考該博客
Hive支持ORCfile奖慌,這是一種新的表格存儲格式抛虫,通過諸如謂詞下推,壓縮等技術(shù)來提高執(zhí)行速度提升简僧。
對于每個HIVE表使用ORCFile應該是一件容易的事情建椰,并且對于獲得HIVE查詢的快速響應時間非常有益。
作為一個例子岛马,考慮兩個大表A和B(作為文本文件存儲广凸,其中一些列未在此處指定,即行試存儲的缺點)以及一個簡單的查詢蛛枚,如:
SELECT A.customerID, A.name, A.age, A.address join
B.role, B.department, B.salary
ON A.customerID=B.customerID;
此查詢可能需要很長時間才能執(zhí)行,因為表A和B都以TEXT形式存儲脸哀,進行全表掃描蹦浦。
將這些表格轉(zhuǎn)換為ORCFile格式通常會顯著減少查詢時間:
1
2
3
4
5
6
7
8
ORC支持壓縮存儲(使用ZLIB或如上所示使用SNAPPY),但也支持未壓縮的存儲撞蜂。
CREATE TABLE A_ORC (
customerID int, name string, age int, address string
) STORED AS ORC tblproperties (“orc.compress" = “SNAPPY”);
INSERT INTO TABLE A_ORC SELECT * FROM A;
CREATE TABLE B_ORC (
customerID int, role string, salary float, department string
) STORED AS ORC tblproperties (“orc.compress" = “SNAPPY”);
INSERT INTO TABLE B_ORC SELECT * FROM B;
SELECT A_ORC.customerID, A_ORC.name,
A_ORC.age, A_ORC.address join
B_ORC.role, B_ORC.department, B_ORC.salary
ON A_ORC.customerID=B_ORC.customerID;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
5.壓縮格式:大數(shù)據(jù)場景下存儲格式壓縮格式尤為關(guān)鍵盲镶,可以提升計算速度,減少存儲空間蝌诡,降低網(wǎng)絡(luò)io溉贿,磁盤io,所以要選擇合適的壓縮格式和存儲格式浦旱,那么首先就了解這些東西宇色,作者以前博客已經(jīng)進行了詳細的說明,參考該博客
6.MAP JOIN
MapJoin簡單說就是在Map階段將小表讀入內(nèi)存颁湖,順序掃描大表完成Join宣蠕。
上圖是Hive MapJoin的原理圖,出自Facebook工程師Liyin Tang的一篇介紹Join優(yōu)化的slice甥捺,從圖中可以看出MapJoin分為兩個階段:
(1)通過MapReduce Local Task抢蚀,將小表讀入內(nèi)存,生成HashTableFiles上傳至Distributed Cache中镰禾,這里會對HashTableFiles進行壓縮皿曲。
(2)MapReduce Job在Map階段唱逢,每個Mapper從Distributed Cache讀取HashTableFiles到內(nèi)存中,順序掃描大表屋休,在Map階段直接進行Join坞古,將數(shù)據(jù)傳遞給下一個MapReduce任務。
也就是在map端進行join避免了shuffle博投。
7.引擎的選擇
Hive可以使用ApacheTez?執(zhí)行引擎而不是古老的Map-Reduce引擎绸贡。
我不會詳細討論在這里提到的使用Tez的許多好處; 相反,我想提出一個簡單的建議:
如果它沒有在您的環(huán)境中默認打開毅哗,請在您的Hive查詢的開頭將以下內(nèi)容設(shè)置為'true'來使用Tez:
設(shè)置hive.execution.engine = tez;
通過上述設(shè)置听怕,您執(zhí)行的每個HIVE查詢都將利用Tez。
目前Hive On Spark還處于試驗階段虑绵,慎用尿瞭。。
1
2
3
4
5
6
8.Use Vectorization
向量化查詢執(zhí)行通過一次性批量執(zhí)行1024行而不是每次單行執(zhí)行翅睛,從而提高掃描声搁,聚合,篩選器和連接等操作的性能捕发。
在Hive 0.13中引入疏旨,此功能顯著提高了查詢執(zhí)行時間,并可通過兩個參數(shù)設(shè)置輕松啟用:
設(shè)置hive.vectorized.execution.enabled = true;
設(shè)置hive.vectorized.execution.reduce.enabled = true;
1
2
3
4
9.cost based query optimization
Hive 自0.14.0開始扎酷,加入了一項”Cost based Optimizer”來對HQL執(zhí)行計劃進行優(yōu)化檐涝,這個功能通
過”hive.cbo.enable”來開啟。在Hive 1.1.0之后法挨,這個feature是默認開啟的,它可以自動優(yōu)化HQL中多個JOIN的順序谁榜,并
選擇合適的JOIN算法.
Hive在提交最終執(zhí)行前,優(yōu)化每個查詢的執(zhí)行邏輯和物理執(zhí)行計劃。這些優(yōu)化工作是交給底層來完成凡纳。
根據(jù)查詢成本執(zhí)行進一步的優(yōu)化窃植,從而產(chǎn)生潛在的不同決策:如何排序連接,執(zhí)行哪種類型的連接荐糜,并行度等等巷怜。
要使用基于成本的優(yōu)化(也稱為CBO),請在查詢開始處設(shè)置以下參數(shù):
設(shè)置hive.cbo.enable = true;
設(shè)置hive.compute.query.using.stats = true;
設(shè)置hive.stats.fetch.column.stats = true;
設(shè)置hive.stats.fetch.partition.stats = true;
1
2
3
4
5
6
7
8
9
10
11
12
13
10.模式選擇
本地模式
對于大多數(shù)情況暴氏,Hive可以通過本地模式在單臺機器上處理所有任務丛版。
對于小數(shù)據(jù),執(zhí)行時間可以明顯被縮短偏序。通過set hive.exec.mode.local.auto=true(默認為false)設(shè)置本地模式页畦。
hive> set hive.exec.mode.local.auto;
hive.exec.mode.local.auto=false
并行模式
Hive會將一個查詢轉(zhuǎn)化成一個或者多個階段。這樣的階段可以是MapReduce階段研儒、抽樣階段豫缨、合并階段独令、limit階段。
默認情況下好芭,Hive一次只會執(zhí)行一個階段燃箭,由于job包含多個階段,而這些階段并非完全互相依賴舍败,
即:這些階段可以并行執(zhí)行招狸,可以縮短整個job的執(zhí)行時間。設(shè)置參數(shù):set hive.exec.parallel=true,或者通過配置文件來完成邻薯。
hive> set hive.exec.parallel;
hive.exec.parallel=false
嚴格模式
Hive提供一個嚴格模式裙戏,可以防止用戶執(zhí)行那些可能產(chǎn)生意想不到的影響查詢,通過設(shè)置
Hive.mapred.modestrict來完成
set Hive.mapred.modestrict;
Hive.mapred.modestrict is undefined
11.JVM重用
Hadoop通常是使用派生JVM來執(zhí)行map和reduce任務的厕诡。這時JVM的啟動過程可能會造成相當大的開銷累榜,
尤其是執(zhí)行的job包含偶成百上千的task任務的情況。JVM重用可以使得JVM示例在同一個job中時候使用N此灵嫌。
通過參數(shù)mapred.job.reuse.jvm.num.tasks來設(shè)置壹罚。
12.推測執(zhí)行
Hadoop推測執(zhí)行可以觸發(fā)執(zhí)行一些重復的任務,盡管因?qū)χ貜偷臄?shù)據(jù)進行計算而導致消耗更多的計算資源寿羞,
不過這個功能的目標是通過加快獲取單個task的結(jié)果以偵測執(zhí)行慢的TaskTracker加入到?jīng)]名單的方式來提高整體的任務執(zhí)行效率猖凛。
Hadoop的推測執(zhí)行功能由2個配置控制著,通過mapred-site.xml中配置
mapred.map.tasks.speculative.execution=true
mapred.reduce.tasks.speculative.execution=true