Hive面試題

1、Hive表關(guān)聯(lián)查詢,如何解決數(shù)據(jù)傾斜的問題?(☆☆☆☆☆)

1)傾斜原因:

map輸出數(shù)據(jù)按key Hash的分配到reduce中,由于key分布不均勻、業(yè)務(wù)數(shù)據(jù)本身的特、建表時(shí)考慮不周、等原因造成的reduce 上的數(shù)據(jù)量差異過大。

(1)key分布不均勻;

(2)業(yè)務(wù)數(shù)據(jù)本身的特性;

(3)建表時(shí)考慮不周;

(4)某些SQL語句本身就有數(shù)據(jù)傾斜;

如何避免:對于key為空產(chǎn)生的數(shù)據(jù)傾斜,可以對其賦予一個(gè)隨機(jī)值。

2)解決方案

(1)參數(shù)調(diào)節(jié):

hive.map.aggr = true

hive.groupby.skewindata=true

有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(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è)過程可以保證相同的 Group By Key 被分布到同一個(gè)Reduce中),最后完成最終的聚合操作。

(2)SQL 語句調(diào)節(jié):

① 選用join key分布最均勻的表作為驅(qū)動(dòng)表。做好列裁剪和filter操作,以達(dá)到兩表做join 的時(shí)候,數(shù)據(jù)量相對變小的效果。

② 大小表Join:

使用map join讓小的維度表(1000 條以下的記錄條數(shù))先進(jìn)內(nèi)存。在map端完成reduce.

③ 大表Join大表:

把空值的key變成一個(gè)字符串加上隨機(jī)數(shù),把傾斜的數(shù)據(jù)分到不同的reduce上,由于null 值關(guān)聯(lián)不上,處理后并不影響最終結(jié)果。

④ count distinct大量相同特殊值:

count distinct 時(shí),將值為空的情況單獨(dú)處理,如果是計(jì)算count distinct,可以不用處理,直接過濾,在最后結(jié)果中加1。如果還有其他計(jì)算,需要進(jìn)行g(shù)roup by,可以先將值為空的記錄單獨(dú)處理,再和其他計(jì)算結(jié)果進(jìn)行union。


----

請說明hive中 Sort By,Order By,Cluster By,Distrbute By各代表什么意思?

order by:會(huì)對輸入做全局排序,因此只有一個(gè)reducer(多個(gè)reducer無法保證全局有序)。只有一個(gè)reducer,會(huì)導(dǎo)致當(dāng)輸入規(guī)模較大時(shí),需要較長的計(jì)算時(shí)間。

sort by:不是全局排序,其在數(shù)據(jù)進(jìn)入reducer前完成排序。

distribute by:按照指定的字段對數(shù)據(jù)進(jìn)行劃分輸出到不同的reduce中。

cluster by:除了具有 distribute by 的功能外還兼具 sort by 的功能。



-----

Hive支持三種不同的元存儲(chǔ)服務(wù)器,分別為:內(nèi)嵌式元存儲(chǔ)服務(wù)器、本地元存儲(chǔ)服務(wù)器、遠(yuǎn)程元存儲(chǔ)服務(wù)器,每種存儲(chǔ)方式使用不同的配置參數(shù)。

內(nèi)嵌式元存儲(chǔ)主要用于單元測試,在該模式下每次只有一個(gè)進(jìn)程可以連接到元存儲(chǔ),Derby是內(nèi)嵌式元存儲(chǔ)的默認(rèn)數(shù)據(jù)庫。

在本地模式下,每個(gè)Hive客戶端都會(huì)打開到數(shù)據(jù)存儲(chǔ)的連接并在該連接上請求SQL查詢。

在遠(yuǎn)程模式下,所有的Hive客戶端都將打開一個(gè)到元數(shù)據(jù)服務(wù)器的連接,該服務(wù)器依次查詢元數(shù)據(jù),元數(shù)據(jù)服務(wù)器和客戶端之間使用Thrift協(xié)議通信。

----------------

Hive內(nèi)部表和外部表的區(qū)別?

創(chuàng)建表時(shí):創(chuàng)建內(nèi)部表時(shí),會(huì)將數(shù)據(jù)移動(dòng)到數(shù)據(jù)倉庫指向的路徑;若創(chuàng)建外部表,僅記錄數(shù)據(jù)所在的路徑, 不對數(shù)據(jù)的位置做任何改變。

刪除表時(shí):在刪除表的時(shí)候,內(nèi)部表的元數(shù)據(jù)和數(shù)據(jù)會(huì)被一起刪除, 而外部表只刪除元數(shù)據(jù),不刪除數(shù)據(jù)。這樣外部表相對來說更加安全些,數(shù)據(jù)組織也更加靈活,方便共享源數(shù)據(jù)。

----

Hive的HSQL轉(zhuǎn)換為MapReduce的過程?(☆☆☆☆☆)

HiveSQL ->AST(抽象語法樹) -> QB(查詢塊) ->OperatorTree(操作樹)->優(yōu)化后的操作樹->mapreduce任務(wù)樹->優(yōu)化后的mapreduce任務(wù)樹




過程描述如下:

SQL Parser:Antlr定義SQL的語法規(guī)則,完成SQL詞法,語法解析,將SQL轉(zhuǎn)化為抽象 語法樹AST Tree;

Semantic Analyzer:遍歷AST Tree,抽象出查詢的基本組成單元QueryBlock;

Logical plan:遍歷QueryBlock,翻譯為執(zhí)行操作樹OperatorTree;

Logical plan optimizer: 邏輯層優(yōu)化器進(jìn)行OperatorTree變換,合并不必要的ReduceSinkOperator,減少shuffle數(shù)據(jù)量;

Physical plan:遍歷OperatorTree,翻譯為MapReduce任務(wù);

Logical plan optimizer:物理層優(yōu)化器進(jìn)行MapReduce任務(wù)的變換,生成最終的執(zhí)行計(jì)劃;


?Hive底層與數(shù)據(jù)庫交互原理?(☆☆☆☆☆)

由于Hive的元數(shù)據(jù)可能要面臨不斷地更新、修改和讀取操作,所以它顯然不適合使用Hadoop文件系統(tǒng)進(jìn)行存儲(chǔ)。目前Hive將元數(shù)據(jù)存儲(chǔ)在RDBMS中,比如存儲(chǔ)在MySQL、Derby中。元數(shù)據(jù)信息包括:存在的表、表的列、權(quán)限和更多的其他信息。





Hive如何進(jìn)行權(quán)限控制?(☆☆☆☆☆)

目前hive支持簡單的權(quán)限管理,默認(rèn)情況下是不開啟,這樣所有的用戶都具有相同的權(quán)限,同時(shí)也是超級管理員,也就對hive中的所有表都有查看和改動(dòng)的權(quán)利,這樣是不符合一般數(shù)據(jù)倉庫的安全原則的。Hive可以是基于元數(shù)據(jù)的權(quán)限管理,也可以基于文件存儲(chǔ)級別的權(quán)限管理。

為了使用Hive的授權(quán)機(jī)制,有兩個(gè)參數(shù)必須在hive-site.xml中設(shè)置:

<property>

<name>hive.security.authorization.enabled</name>

<value>true</value>

<description>enable or disable the hive client authorization</description>

</property>

<property>

<name>hive.security.authorization.createtable.owner.grants</name>

<value>ALL</value>

<description>the privileges automatically granted to the owner whenever a table gets created. An example like "select,drop" will grant select and drop privilege to the owner of the table</description>

</property>

Hive支持以下權(quán)限:


Hive授權(quán)的核心就是用戶(user)、組(group)、角色(role)。

Hive中的角色和平常我們認(rèn)知的角色是有區(qū)別的,Hive中的角色可以理解為一部分有一些相同“屬性”的用戶或組或角色的集合。這里有個(gè)遞歸的概念,就是一個(gè)角色可以是一些角色的集合。


---

Hive 中的壓縮格式TextFile、SequenceFile、RCfile 、ORCfile各有什么區(qū)別?

1. TextFile

默認(rèn)格式,存儲(chǔ)方式為行存儲(chǔ),數(shù)據(jù)不做壓縮,磁盤開銷大,數(shù)據(jù)解析開銷大。 可結(jié)合Gzip、Bzip2使用(系統(tǒng)自動(dòng)檢查,執(zhí)行查詢時(shí)自動(dòng)解壓),但使用這種方式,壓縮后的文件不支持split,Hive不會(huì)對數(shù)據(jù)進(jìn)行切分,從而無法對數(shù)據(jù)進(jìn)行并行操作。并且在反序列化過程中,必須逐個(gè)字符判斷是不是分隔符和行結(jié)束符,因此反序列化開銷會(huì)比SequenceFile高幾十倍。

2. SequenceFile

SequenceFile是Hadoop API提供的一種二進(jìn)制文件支持,,存儲(chǔ)方式為行存儲(chǔ),其具有使用方便、可分割、可壓縮的特點(diǎn)。

SequenceFile支持三種壓縮選擇:NONE,RECORD,BLOCK。Record壓縮率低,一般建議使用BLOCK壓縮。

優(yōu)勢是文件和hadoop api中的MapFile是相互兼容的

3. RCFile

存儲(chǔ)方式:數(shù)據(jù)按行分塊,每塊按列存儲(chǔ)。結(jié)合了行存儲(chǔ)和列存儲(chǔ)的優(yōu)點(diǎn):

首先,RCFile 保證同一行的數(shù)據(jù)位于同一節(jié)點(diǎn),因此元組重構(gòu)的開銷很低;

其次,像列存儲(chǔ)一樣,RCFile 能夠利用列維度的數(shù)據(jù)壓縮,并且能跳過不必要的列讀??;


RCFile的一個(gè)行組包括三個(gè)部分:

第一部分是行組頭部的【同步標(biāo)識】,主要用于分隔 hdfs 塊中的兩個(gè)連續(xù)行組

第二部分是行組的【元數(shù)據(jù)頭部】,用于存儲(chǔ)行組單元的信息,包括行組中的記錄數(shù)、每個(gè)列的字節(jié)數(shù)、列中每個(gè)域的字節(jié)數(shù)

第三部分是【表格數(shù)據(jù)段】,即實(shí)際的列存儲(chǔ)數(shù)據(jù)。在該部分中,同一列的所有域順序存儲(chǔ)。


從圖可以看出,首先存儲(chǔ)了列 A 的所有域,然后存儲(chǔ)列 B 的所有域等。




數(shù)據(jù)追加:RCFile 不支持任意方式的數(shù)據(jù)寫操作,僅提供一種追加接口,這是因?yàn)榈讓拥?HDFS當(dāng)前僅僅支持?jǐn)?shù)據(jù)追加寫文件尾部。

行組大?。盒薪M變大有助于提高數(shù)據(jù)壓縮的效率,但是可能會(huì)損害數(shù)據(jù)的讀取性能,因?yàn)檫@樣增加了 Lazy 解壓性能的消耗。而且行組變大會(huì)占用更多的內(nèi)存,這會(huì)影響并發(fā)執(zhí)行的其他MR作業(yè)。 考慮到存儲(chǔ)空間和查詢效率兩個(gè)方面,F(xiàn)acebook 選擇 4MB 作為默認(rèn)的行組大小,當(dāng)然也允許用戶自行選擇參數(shù)進(jìn)行配置。

1. ORCFile

存儲(chǔ)方式:數(shù)據(jù)按行分塊 每塊按照列存儲(chǔ)。

壓縮快 快速列存取。

效率比rcfile高,是rcfile的改良版本。

以下為RCFile、TextFile、SequenceFile三種文件的存儲(chǔ)情況:

總結(jié):相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存儲(chǔ)方式,數(shù)據(jù)加載時(shí)性能消耗較大,但是具有較好的壓縮比和查詢響應(yīng)。

數(shù)據(jù)倉庫的特點(diǎn)是一次寫入、多次讀取,因此,整體來看,RCFILE相比其余兩種格式具有較明顯的優(yōu)勢。

----

Hive?join過程中大表小表的放置順序?

將最大的表放置在JOIN語句的最右邊,或者直接使用/*+ streamtable(table_name) */指出。

在編寫帶有 join 操作的代碼語句時(shí),應(yīng)該將條目少的表/子查詢放在 Join 操作符的左邊。因?yàn)樵?Reduce 階段,位于 Join 操作符左邊的表的內(nèi)容會(huì)被加載進(jìn)內(nèi)存,載入條目較少的表可以有效減少 OOM(out of memory)即內(nèi)存溢出。所以對于同一個(gè) key 來說,對應(yīng)的 value 值小的放前,大的放后,這便是“小表放前”原則。若一條語句中有多個(gè) Join,依據(jù) Join 的條件相同與否,有不同的處理方法。

-----

Hive的兩張表關(guān)聯(lián),使用MapReduce怎么實(shí)現(xiàn)?(☆☆☆☆☆)

如果其中有一張表為小表,直接使用map端join的方式(map端加載小表)進(jìn)行聚合。

如果兩張都是大表,那么采用聯(lián)合key,聯(lián)合key的第一個(gè)組成部分是join on中的公共字段,第二部分是一個(gè)flag,0代表表A,1代表表B,由此讓Reduce區(qū)分客戶信息和訂單信息;在Mapper中同時(shí)處理兩張表的信息,將join on公共字段相同的數(shù)據(jù)劃分到同一個(gè)分區(qū)中,進(jìn)而傳遞到一個(gè)Reduce中,然后在Reduce中實(shí)現(xiàn)聚合。

-----

Hive自定義UDF函數(shù)的流程?

1)寫一個(gè)類繼承(org.apache.hadoop.hive.ql.)UDF類;

2)覆蓋方法evaluate();

3)打JAR包;

4)通過hive命令將JAR添加到Hive的類路徑:

hive> add jar /home/ubuntu/ToDate.jar;

5)注冊函數(shù):

hive> create temporary function xxx as 'XXX';

6)使用函數(shù);

7)[可選] drop臨時(shí)函數(shù);

-----

Hive優(yōu)化措施(☆☆☆☆☆)

1、 Fetch抓取

Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計(jì)算。例如:SELECT * FROM employees;在這種情況下,Hive可以簡單地讀取employee對應(yīng)的存儲(chǔ)目錄下的文件,然后輸出查詢結(jié)果到控制臺(tái)。

在hive-default.xml.template文件中hive.fetch.task.conversion默認(rèn)是more,老版本hive默認(rèn)是minimal,該屬性修改為more以后,在全局查找、字段查找、limit查找等都不走mapreduce。

<property>

? ? <name>hive.fetch.task.conversion</name>

? ? <value>more</value>

? ? <description>

? ? ? Expects one of [none, minimal, more].

? ? ? Some select queries can be converted to single FETCH task minimizing latency.

? ? ? Currently the query should be single sourced not having any subquery and should not have

? ? ? any aggregations or distincts (which incurs RS), lateral views and joins.

? ? ? 0. none : disable hive.fetch.task.conversion

? ? ? 1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only

? ? ? 2. more? : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)

? ? </description>

? </property>

案例實(shí)操:

1)把hive.fetch.task.conversion設(shè)置成none,然后執(zhí)行查詢語句,都會(huì)執(zhí)行mapreduce程序。

hive (default)> set hive.fetch.task.conversion=none;

hive (default)> select * from emp;

hive (default)> select ename from emp;

hive (default)> select ename from emp limit 3;

2)把hive.fetch.task.conversion設(shè)置成more,然后執(zhí)行查詢語句,如下查詢方式都不會(huì)執(zhí)行mapreduce程序。

hive (default)> set hive.fetch.task.conversion=more;

hive (default)> select * from emp;

hive (default)> select ename from emp;

hive (default)> select ename from emp limit 3;


2 ,本地模式

大多數(shù)的Hadoop Job是需要Hadoop提供的完整的可擴(kuò)展性來處理大數(shù)據(jù)集的。不過,有時(shí)Hive的輸入數(shù)據(jù)量是非常小的。在這種情況下,為查詢觸發(fā)執(zhí)行任務(wù)時(shí)消耗可能會(huì)比實(shí)際job的執(zhí)行時(shí)間要多的多。對于大多數(shù)這種情況,Hive可以通過本地模式在單臺(tái)機(jī)器上處理所有的任務(wù)。對于小數(shù)據(jù)集,執(zhí)行時(shí)間可以明顯被縮短。

用戶可以通過設(shè)置hive.exec.mode.local.auto的值為true,來讓Hive在適當(dāng)?shù)臅r(shí)候自動(dòng)啟動(dòng)這個(gè)優(yōu)化。

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;

案例實(shí)操:

1)開啟本地模式,并執(zhí)行查詢語句

hive (default)> set hive.exec.mode.local.auto=true;

hive (default)> select * from emp cluster by deptno;

Time taken: 1.328 seconds, Fetched: 14 row(s)

2)關(guān)閉本地模式,并執(zhí)行查詢語句

hive (default)> set hive.exec.mode.local.auto=false;

hive (default)> select * from emp cluster by deptno;

Time taken: 20.09 seconds, Fetched: 14 row(s)

(3)?表的優(yōu)化

小表、大表Join

將key相對分散,并且數(shù)據(jù)量小的表放在join的左邊,這樣可以有效減少內(nèi)存溢出錯(cuò)誤發(fā)生的幾率;再進(jìn)一步,可以使用Group讓小的維度表(1000條以下的記錄條數(shù))先進(jìn)內(nèi)存。在map端完成reduce。

實(shí)際測試發(fā)現(xiàn):新版的hive已經(jīng)對小表JOIN大表和大表JOIN小表進(jìn)行了優(yōu)化。小表放在左邊和右邊已經(jīng)沒有明顯區(qū)別。

案例實(shí)操

(0)需求:測試大表JOIN小表和小表JOIN大表的效率

(1)建大表、小表和JOIN后表的語句

create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

create table smalltable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

(2)分別向大表和小表中導(dǎo)入數(shù)據(jù)

hive (default)> load data local inpath '/opt/module/datas/bigtable' into table bigtable;

hive (default)>load data local inpath '/opt/module/datas/smalltable' into table smalltable;

(3)關(guān)閉mapjoin功能(默認(rèn)是打開的)

set hive.auto.convert.join = false;

(4)執(zhí)行小表JOIN大表語句

insert overwrite table jointable

select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url

from smalltable s

left join bigtable? b

on b.id = s.id;

Time taken: 35.921 seconds

(5)執(zhí)行大表JOIN小表語句

insert overwrite table jointable

select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url

from bigtable? b

left join smalltable? s

on s.id = b.id;

Time taken: 34.196 seconds

(2)大表Join大表

1)空KEY過濾

有時(shí)join超時(shí)是因?yàn)槟承﹌ey對應(yīng)的數(shù)據(jù)太多,而相同key對應(yīng)的數(shù)據(jù)都會(huì)發(fā)送到相同的reducer上,從而導(dǎo)致內(nèi)存不夠。此時(shí)我們應(yīng)該仔細(xì)分析這些異常的key,很多情況下,這些key對應(yīng)的數(shù)據(jù)是異常數(shù)據(jù),我們需要在SQL語句中進(jìn)行過濾。例如key對應(yīng)的字段為空,操作如下:

案例實(shí)操

(1)配置歷史服務(wù)器

配置mapred-site.xml

<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://192.168.1.102:19888/jobhistory192.168.1.102:19888/jobhistory

(2)創(chuàng)建原始數(shù)據(jù)表、空id表、合并后數(shù)據(jù)表

create table ori(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

create table nullidtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

(3)分別加載原始數(shù)據(jù)和空id數(shù)據(jù)到對應(yīng)表中

hive (default)> load data local inpath '/opt/module/datas/ori' into table ori;

hive (default)> load data local inpath '/opt/module/datas/nullid' into table nullidtable;

(4)測試不過濾空id

hive (default)> insert overwrite table jointable

select n.* from nullidtable n left join ori o on n.id = o.id;

Time taken: 42.038 seconds

(5)測試過濾空id

hive (default)> insert overwrite table jointable

select n.* from (select * from nullidtable where id is not null ) n? left join ori o on n.id = o.id;

Time taken: 31.725 seconds

2)空key轉(zhuǎn)換

有時(shí)雖然某個(gè)key為空對應(yīng)的數(shù)據(jù)很多,但是相應(yīng)的數(shù)據(jù)不是異常數(shù)據(jù),必須要包含在join的結(jié)果中,此時(shí)我們可以表a中key為空的字段賦一個(gè)隨機(jī)的值,使得數(shù)據(jù)隨機(jī)均勻地分不到不同的reducer上。例如:

案例實(shí)操:

不隨機(jī)分布空null值:

(1)設(shè)置5個(gè)reduce個(gè)數(shù)

set mapreduce.job.reduces = 5;

(2)JOIN兩張表

insert overwrite table jointable

select n.* from nullidtable n left join ori b on n.id = b.id;

結(jié)果:可以看出來,出現(xiàn)了數(shù)據(jù)傾斜,某些reducer的資源消耗遠(yuǎn)大于其他reducer。

隨機(jī)分布空null值

(1)設(shè)置5個(gè)reduce個(gè)數(shù)

set mapreduce.job.reduces = 5;

(2)JOIN兩張表

nsert overwrite table jointable

select n.* from nullidtable n full join ori o on

case when n.id is null then concat('hive', rand()) else n.id end = o.id;

結(jié)果:可以看出來,消除了數(shù)據(jù)傾斜,負(fù)載均衡reducer的資源消耗

------

3 MapJoin

如果不指定MapJoin或者不符合MapJoin的條件,那么Hive解析器會(huì)將Join操作轉(zhuǎn)換成Common Join,即:在Reduce階段完成join。容易發(fā)生數(shù)據(jù)傾斜。可以用MapJoin把小表全部加載到內(nèi)存在map端進(jìn)行join,避免reducer處理。

1)開啟MapJoin參數(shù)設(shè)置:

(1)設(shè)置自動(dòng)選擇Mapjoin

set hive.auto.convert.join = true; 默認(rèn)為true

(2)大表小表的閥值設(shè)置(默認(rèn)25M一下認(rèn)為是小表):

set hive.mapjoin.smalltable.filesize=25000000;

2)MapJoin工作機(jī)制


先是Task A,它是一個(gè)Local Task(在客戶端本地執(zhí)行的Task),負(fù)責(zé)掃描小表b的數(shù)據(jù),將其轉(zhuǎn)換成一個(gè)HashTable的數(shù)據(jù)結(jié)構(gòu),并寫入本地的文件中,之后將該文件加載到DistributeCache中。

接下來是Task B,該任務(wù)是一個(gè)沒有Reduce的MR,啟動(dòng)MapTasks掃描大表a,在Map階段,根據(jù)a的每一條記錄去和DistributeCache中b表對應(yīng)的HashTable關(guān)聯(lián),并直接輸出結(jié)果。

由于MapJoin沒有Reduce,所以由Map直接輸出結(jié)果文件,有多少個(gè)Map Task,就有多少個(gè)結(jié)果文件。

案例實(shí)操:

(1)開啟Mapjoin功能

set hive.auto.convert.join = true; 默認(rèn)為true

(2)執(zhí)行小表JOIN大表語句

insert overwrite table jointable

select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url

from smalltable s

join bigtable? b

on s.id = b.id;

Time taken: 24.594 seconds

(3)執(zhí)行大表JOIN小表語句

insert overwrite table jointable

select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url

from bigtable? b

join smalltable? s

on s.id = b.id;

Time taken: 24.315 seconds

(4) Group By

默認(rèn)情況下,Map階段同一Key數(shù)據(jù)分發(fā)給一個(gè)reduce,當(dāng)一個(gè)key數(shù)據(jù)過大時(shí)就傾斜了。

并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端進(jìn)行部分聚合,最后在Reduce端得出最終結(jié)果。

1)開啟Map端聚合參數(shù)設(shè)置

(1)是否在Map端進(jìn)行聚合,默認(rèn)為True

hive.map.aggr = true

(2)在Map端進(jìn)行聚合操作的條目數(shù)目

? ? hive.groupby.mapaggr.checkinterval = 100000

(3)有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(fù)載均衡(默認(rèn)是false)

? ? hive.groupby.skewindata = true

當(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è)過程可以保證相同的Group By Key被分布到同一個(gè)Reduce中),最后完成最終的聚合操作。

(5)?Count(Distinct) 去重統(tǒng)計(jì)

數(shù)據(jù)量小的時(shí)候無所謂,數(shù)據(jù)量大的情況下,由于COUNT DISTINCT操作需要用一個(gè)Reduce Task來完成,這一個(gè)Reduce需要處理的數(shù)據(jù)量太大,就會(huì)導(dǎo)致整個(gè)Job很難完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換:

案例實(shí)操

(1)創(chuàng)建一張大表

hive (default)> create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';

(2)加載數(shù)據(jù)

hive (default)> load data local inpath '/opt/module/datas/bigtable' into table bigtable;

(3)設(shè)置5個(gè)reduce個(gè)數(shù)

set mapreduce.job.reduces = 5;

(4)執(zhí)行去重id查詢

hive (default)> select count(distinct id) from bigtable;

Stage-Stage-1: Map: 1? Reduce: 1? Cumulative CPU: 7.12 sec? HDFS Read: 120741990 HDFS Write: 7 SUCCESS

Total MapReduce CPU Time Spent: 7 seconds 120 msec

OK

c0

100001

Time taken: 23.607 seconds, Fetched: 1 row(s)

Time taken: 34.941 seconds, Fetched: 1 row(s)

(5)采用GROUP by去重id

hive (default)> select count(id) from (select id from bigtable group by id) a;

Stage-Stage-1: Map: 1? Reduce: 5? Cumulative CPU: 17.53 sec? HDFS Read: 120752703 HDFS Write: 580 SUCCESS

Stage-Stage-2: Map: 3? Reduce: 1? Cumulative CPU: 4.29 sec? HDFS Read: 9409 HDFS Write: 7 SUCCESS

Total MapReduce CPU Time Spent: 21 seconds 820 msec

OK

_c0

100001

Time taken: 50.795 seconds, Fetched: 1 row(s)

雖然會(huì)多用一個(gè)Job來完成,但在數(shù)據(jù)量大的情況下,這個(gè)絕對是值得的。

(6) 笛卡爾積

盡量避免笛卡爾積,join的時(shí)候不加on條件,或者無效的on條件,Hive只能使用1個(gè)reducer來完成笛卡爾積

(7)行列過濾

列處理:在SELECT中,只拿需要的列,如果有,盡量使用分區(qū)過濾,少用SELECT *。

行處理:在分區(qū)剪裁中,當(dāng)使用外關(guān)聯(lián)時(shí),如果將副表的過濾條件寫在Where后面,那么就會(huì)先全表關(guān)聯(lián),之后再過濾,比如:

案例實(shí)操:

(1)測試先關(guān)聯(lián)兩張表,再用where條件過濾

hive (default)> select o.id from bigtable b

join ori o on o.id = b.id

where o.id <= 10;

Time taken: 34.406 seconds, Fetched: 100 row(s)

Time taken: 26.043 seconds, Fetched: 100 row(s)

(2)通過子查詢后,再關(guān)聯(lián)表

hive (default)> select b.id from bigtable b

join (select id from ori where id <= 10 ) o on b.id = o.id;

Time taken: 30.058 seconds, Fetched: 100 row(s)

Time taken: 29.106 seconds, Fetched: 100 row(s)

(8)動(dòng)態(tài)分區(qū)調(diào)整

關(guān)系型數(shù)據(jù)庫中,對分區(qū)表Insert數(shù)據(jù)時(shí)候,數(shù)據(jù)庫自動(dòng)會(huì)根據(jù)分區(qū)字段的值,將數(shù)據(jù)插入到相應(yīng)的分區(qū)中,Hive中也提供了類似的機(jī)制,即動(dòng)態(tài)分區(qū)(Dynamic Partition),只不過,使用Hive的動(dòng)態(tài)分區(qū),需要進(jìn)行相應(yīng)的配置。

1)開啟動(dòng)態(tài)分區(qū)參數(shù)設(shè)置

(1)開啟動(dòng)態(tài)分區(qū)功能(默認(rèn)true,開啟)

hive.exec.dynamic.partition=true

(2)設(shè)置為非嚴(yán)格模式(動(dòng)態(tài)分區(qū)的模式,默認(rèn)strict,表示必須指定至少一個(gè)分區(qū)為靜態(tài)分區(qū),nonstrict模式表示允許所有的分區(qū)字段都可以使用動(dòng)態(tài)分區(qū)。)

hive.exec.dynamic.partition.mode=nonstrict

(3)在所有執(zhí)行MR的節(jié)點(diǎn)上,最大一共可以創(chuàng)建多少個(gè)動(dòng)態(tài)分區(qū)。

hive.exec.max.dynamic.partitions=1000

(4)在每個(gè)執(zhí)行MR的節(jié)點(diǎn)上,最大可以創(chuàng)建多少個(gè)動(dòng)態(tài)分區(qū)。該參數(shù)需要根據(jù)實(shí)際的數(shù)據(jù)來設(shè)定。比如:源數(shù)據(jù)中包含了一年的數(shù)據(jù),即day字段有365個(gè)值,那么該參數(shù)就需要設(shè)置成大于365,如果使用默認(rèn)值100,則會(huì)報(bào)錯(cuò)。

hive.exec.max.dynamic.partitions.pernode=100

(5)整個(gè)MR Job中,最大可以創(chuàng)建多少個(gè)HDFS文件。

hive.exec.max.created.files=100000

(6)當(dāng)有空分區(qū)生成時(shí),是否拋出異常。一般不需要設(shè)置。

hive.error.on.empty.partition=false

2)案例實(shí)操

需求:將ori中的數(shù)據(jù)按照時(shí)間(如:20111230000008),插入到目標(biāo)表ori_partitioned_target的相應(yīng)分區(qū)中。

(1)創(chuàng)建分區(qū)表

create table ori_partitioned(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string)

partitioned by (p_time bigint)

row format delimited fields terminated by '\t';

(2)加載數(shù)據(jù)到分區(qū)表中

hive (default)> load data local inpath '/opt/module/datas/ds1' into table ori_partitioned partition(p_time='20111230000010') ;

hive (default)> load data local inpath '/opt/module/datas/ds2' into table ori_partitioned partition(p_time='20111230000011') ;

(3)創(chuàng)建目標(biāo)分區(qū)表

create table ori_partitioned_target(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) PARTITIONED BY (p_time STRING) row format delimited fields terminated by '\t';

(4)設(shè)置動(dòng)態(tài)分區(qū)

set hive.exec.dynamic.partition = true;

set hive.exec.dynamic.partition.mode = nonstrict;

set hive.exec.max.dynamic.partitions = 1000;

set hive.exec.max.dynamic.partitions.pernode = 100;

set hive.exec.max.created.files = 100000;

set hive.error.on.empty.partition = false;

hive (default)> insert overwrite table ori_partitioned_target partition (p_time)

select id, time, uid, keyword, url_rank, click_num, click_url, p_time from ori_partitioned;

(5)查看目標(biāo)分區(qū)表的分區(qū)情況

hive (default)> show partitions ori_partitioned_target;



4、?數(shù)據(jù)傾斜

1) Map數(shù)

(1)通常情況下,作業(yè)會(huì)通過input的目錄產(chǎn)生一個(gè)或者多個(gè)map任務(wù)。

主要的決定因素有:input的文件總個(gè)數(shù),input的文件大小,集群設(shè)置的文件塊大小。

(2)是不是map數(shù)越多越好?

答案是否定的。如果一個(gè)任務(wù)有很多小文件(遠(yuǎn)遠(yuǎn)小于塊大小128m),則每個(gè)小文件也會(huì)被當(dāng)做一個(gè)塊,用一個(gè)map任務(wù)來完成,而一個(gè)map任務(wù)啟動(dòng)和初始化的時(shí)間遠(yuǎn)遠(yuǎn)大于邏輯處理的時(shí)間,就會(huì)造成很大的資源浪費(fèi)。而且,同時(shí)可執(zhí)行的map數(shù)是受限的。

(3)是不是保證每個(gè)map處理接近128m的文件塊,就高枕無憂了?

答案也是不一定。比如有一個(gè)127m的文件,正常會(huì)用一個(gè)map去完成,但這個(gè)文件只有一個(gè)或者兩個(gè)小字段,卻有幾千萬的記錄,如果map處理的邏輯比較復(fù)雜,用一個(gè)map任務(wù)去做,肯定也比較耗時(shí)。

針對上面的問題2和3,我們需要采取兩種方式來解決:即減少map數(shù)和增加map數(shù);

2)小文件進(jìn)行合并

在map執(zhí)行前合并小文件,減少map數(shù):CombineHiveInputFormat具有對小文件進(jìn)行合并的功能(系統(tǒng)默認(rèn)的格式)。HiveInputFormat沒有對小文件合并功能。

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

3)復(fù)雜文件增加Map數(shù)

當(dāng)input的文件都很大,任務(wù)邏輯復(fù)雜,map執(zhí)行非常慢的時(shí)候,可以考慮增加Map數(shù),來使得每個(gè)map處理的數(shù)據(jù)量減少,從而提高任務(wù)的執(zhí)行效率。

增加map的方法為:根據(jù)

computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M

公式,調(diào)整maxSize最大值。讓maxSize最大值低于blocksize就可以增加map的個(gè)數(shù)。

案例實(shí)操:

(1)執(zhí)行查詢

hive (default)> select count(*) from emp;

Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1

(2)設(shè)置最大切片值為100個(gè)字節(jié)

hive (default)> set mapreduce.input.fileinputformat.split.maxsize=100;

hive (default)> select count(*) from emp;

Hadoop job information for Stage-1: number of mappers: 6; number of reducers: 1

4) Reduce數(shù)

(1)調(diào)整reduce個(gè)數(shù)方法一

1、每個(gè)Reduce處理的數(shù)據(jù)量默認(rèn)是256MB

hive.exec.reducers.bytes.per.reducer=256000000

2、每個(gè)任務(wù)最大的reduce數(shù),默認(rèn)為1009

hive.exec.reducers.max=1009

3、計(jì)算reducer數(shù)的公式

N=min(參數(shù)2,總輸入數(shù)據(jù)量/參數(shù)1)

(2)調(diào)整reduce個(gè)數(shù)方法二

在hadoop的mapred-default.xml文件中修改

設(shè)置每個(gè)job的Reduce個(gè)數(shù)

set mapreduce.job.reduces = 15;

(3)reduce個(gè)數(shù)并不是越多越好

1、過多的啟動(dòng)和初始化reduce也會(huì)消耗時(shí)間和資源;

2、另外,有多少個(gè)reduce,就會(huì)有多少個(gè)輸出文件,如果生成了很多個(gè)小文件,那么如果這些小文件作為下一個(gè)任務(wù)的輸入,則也會(huì)出現(xiàn)小文件過多的問題;

在設(shè)置reduce個(gè)數(shù)的時(shí)候也需要考慮這兩個(gè)原則:處理大數(shù)據(jù)量利用合適的reduce數(shù);使單個(gè)reduce任務(wù)處理數(shù)據(jù)量大小要合適;

5)并行執(zhí)行

Hive會(huì)將一個(gè)查詢轉(zhuǎn)化成一個(gè)或者多個(gè)階段。這樣的階段可以是MapReduce階段、抽樣階段、合并階段、limit階段?;蛘逪ive執(zhí)行過程中可能需要的其他階段。默認(rèn)情況下,Hive一次只會(huì)執(zhí)行一個(gè)階段。不過,某個(gè)特定的job可能包含眾多的階段,而這些階段可能并非完全互相依賴的,也就是說有些階段是可以并行執(zhí)行的,這樣可能使得整個(gè)job的執(zhí)行時(shí)間縮短。不過,如果有更多的階段可以并行執(zhí)行,那么job可能就越快完成。

通過設(shè)置參數(shù)hive.exec.parallel值為true,就可以開啟并發(fā)執(zhí)行。不過,在共享集群中,需要注意下,如果job中并行階段增多,那么集群利用率就會(huì)增加。

set hive.exec.parallel=true;? ? ? ? ? ? ? //打開任務(wù)并行執(zhí)行

set hive.exec.parallel.thread.number=16;? //同一個(gè)sql允許最大并行度,默認(rèn)為8。

當(dāng)然,得是在系統(tǒng)資源比較空閑的時(shí)候才有優(yōu)勢,否則,沒資源,并行也起不來。

6)?嚴(yán)格模式

Hive提供了一個(gè)嚴(yán)格模式,可以防止用戶執(zhí)行那些可能意向不到的不好的影響的查詢。

通過設(shè)置屬性hive.mapred.mode值為默認(rèn)是非嚴(yán)格模式nonstrict 。開啟嚴(yán)格模式需要修改hive.mapred.mode值為strict,開啟嚴(yán)格模式可以禁止3種類型的查詢。

<property>

? ? <name>hive.mapred.mode</name>

? ? <value>strict</value>

? ? <description>

? ? ? The mode in which the Hive operations are being performed.

? ? ? In strict mode, some risky queries are not allowed to run. They include:

? ? ? ? Cartesian Product.

? ? ? ? No partition being picked up for a query.

? ? ? ? Comparing bigints and strings.

? ? ? ? Comparing bigints and doubles.

? ? ? ? Orderby without limit.

? ? </description>

? </property>

(1)對于分區(qū)表,除非where語句中含有分區(qū)字段過濾條件來限制范圍,否則不允許執(zhí)行。換句話說,就是用戶不允許掃描所有分區(qū)。進(jìn)行這個(gè)限制的原因是,通常分區(qū)表都擁有非常大的數(shù)據(jù)集,而且數(shù)據(jù)增加迅速。沒有進(jìn)行分區(qū)限制的查詢可能會(huì)消耗令人不可接受的巨大資源來處理這個(gè)表。

(2)對于使用了order by語句的查詢,要求必須使用limit語句。因?yàn)閛rder by為了執(zhí)行排序過程會(huì)將所有的結(jié)果數(shù)據(jù)分發(fā)到同一個(gè)Reducer中進(jìn)行處理,強(qiáng)制要求用戶增加這個(gè)LIMIT語句可以防止Reducer額外執(zhí)行很長一段時(shí)間。

(3)限制笛卡爾積的查詢。對關(guān)系型數(shù)據(jù)庫非常了解的用戶可能期望在執(zhí)行JOIN查詢的時(shí)候不使用ON語句而是使用where語句,這樣關(guān)系數(shù)據(jù)庫的執(zhí)行優(yōu)化器就可以高效地將WHERE語句轉(zhuǎn)化成那個(gè)ON語句。不幸的是,Hive并不會(huì)執(zhí)行這種優(yōu)化,因此,如果表足夠大,那么這個(gè)查詢就會(huì)出現(xiàn)不可控的情況。

7) JVM重用

JVM重用是Hadoop調(diào)優(yōu)參數(shù)的內(nèi)容,其對Hive的性能具有非常大的影響,特別是對于很難避免小文件的場景或task特別多的場景,這類場景大多數(shù)執(zhí)行時(shí)間都很短。

Hadoop的默認(rèn)配置通常是使用派生JVM來執(zhí)行map和Reduce任務(wù)的。這時(shí)JVM的啟動(dòng)過程可能會(huì)造成相當(dāng)大的開銷,尤其是執(zhí)行的job包含有成百上千task任務(wù)的情況。JVM重用可以使得JVM實(shí)例在同一個(gè)job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中進(jìn)行配置。通常在10-20之間,具體多少需要根據(jù)具體業(yè)務(wù)場景測試得出。

<property>

? <name>mapreduce.job.jvm.numtasks</name>

? <value>10</value>

? <description>How many tasks to run per jvm. If set to -1, there is

? no limit.

? </description>

</property>

這個(gè)功能的缺點(diǎn)是,開啟JVM重用將一直占用使用到的task插槽,以便進(jìn)行重用,直到任務(wù)完成后才能釋放。如果某個(gè)“不平衡的”job中有某幾個(gè)reduce task執(zhí)行的時(shí)間要比其他Reduce task消耗的時(shí)間多的多的話,那么保留的插槽就會(huì)一直空閑著卻無法被其他的job使用,直到所有的task都結(jié)束了才會(huì)釋放。

8)?推測執(zhí)行

在分布式集群環(huán)境下,因?yàn)槌绦駼ug(包括Hadoop本身的bug),負(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采用了推測執(zhí)行(Speculative Execution)機(jī)制,它根據(jù)一定的法則推測出“拖后腿”的任務(wù),并為這樣的任務(wù)啟動(dòng)一個(gè)備份任務(wù),讓該任務(wù)與原始任務(wù)同時(shí)處理同一份數(shù)據(jù),并最終選用最先成功運(yùn)行完成任務(wù)的計(jì)算結(jié)果作為最終結(jié)果。

設(shè)置開啟推測執(zhí)行參數(shù):Hadoop的mapred-site.xml文件中進(jìn)行配置

<property>

? <name>mapreduce.map.speculative</name>

? <value>true</value>

? <description>If true, then multiple instances of some map tasks

? ? ? ? ? ? ? may be executed in parallel.</description>

</property>

<property>

? <name>mapreduce.reduce.speculative</name>

? <value>true</value>

? <description>If true, then multiple instances of some reduce tasks

? ? ? ? ? ? ? may be executed in parallel.</description>

</property>

不過hive本身也提供了配置項(xiàng)來控制reduce-side的推測執(zhí)行:

? <property>

? ? <name>hive.mapred.reduce.tasks.speculative.execution</name>

? ? <value>true</value>

? ? <description>Whether speculative execution for reducers should be turned on. </description>

? </property>

關(guān)于調(diào)優(yōu)這些推測執(zhí)行變量,還很難給一個(gè)具體的建議。如果用戶對于運(yùn)行時(shí)的偏差非常敏感的話,那么可以將這些功能關(guān)閉掉。如果用戶因?yàn)檩斎霐?shù)據(jù)量很大而需要執(zhí)行長時(shí)間的map或者Reduce task的話,那么啟動(dòng)推測執(zhí)行造成的浪費(fèi)是非常巨大大。

9)?壓縮

詳見第8章。

10) EXPLAIN(執(zhí)行計(jì)劃)

(1)基本語法

EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query

(2)案例實(shí)操

1、查看下面這條語句的執(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;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容