http://blog.sina.com.cn/s/blog_6a7df1f1010197d2.html
在Hive中萎战,某些小技巧可以讓我們的Job執(zhí)行得更快分瘾,有時一點小小的改動就可以讓性能得到大幅提升,這一點其實跟SQL差不多叠聋。
首先柒爸,Hive != SQL,雖然二者的語法很像西傀,但是Hive最終會被轉化成MapReduce的代碼去執(zhí)行斤寇,所以數據庫的優(yōu)化原則基本上都不適用于 Hive。也正因如此拥褂,Hive實際上是用來做計算的娘锁,而不像數據庫是用作存儲的,當然數據庫也有很多計算功能饺鹃,但一般并不建議在SQL中大量使用計算莫秆,把數據庫只當作存儲是一個很重要的原則。
一悔详、善用臨時表
在處理海量數據時我們通常會對很多大表進行操作镊屎,基于Hadoop現(xiàn)在的局限性,不能像分布式并行數據庫那樣很好地在分布式環(huán)境利用數據局部性茄螃,Hadoop對于大表只能全表掃描并篩選數據缝驳,而每一次對大表的掃描都是苦不堪言的。(最后知道真相的我眼淚掉下來。用狱。运怖。)
所以我們會用到在編碼中經常用到的重構技巧,提取公共變量夏伊,在Hive中摇展,就是創(chuàng)建臨時表。
例如:現(xiàn)在要對三個表A溺忧、B咏连、C進行處理,Hive QL是:
select T1., T2. from
(select id, name from A) T1
join
(select id, price, feedback, type from B) T2
on T1.id = T2.id;
select T1., T2. from
(select id, type from C) T1
join
(select id, price,feedback, attribute from B) T2
on T1.id = T2.id;
這里A表和C表只會被掃描一次鲁森,而B表會被掃描兩次捻勉,如果B表的數據量很大,那么掃描B表的時間將會占用很大一塊刀森。
這里我們可以先創(chuàng)建一個臨時表:
create table temp_B as select id, price, feedback, type, attribute from B;
這個表只有B表的部分字段,所以大小會小很多报账,這里會對B表全表掃一遍研底。
然后可以用臨時表和A、C表做join運算:
select T1., T2. from
(select id, name from A) T1
join
(select id, price, feedback, type from temp_B) T2
on T1.id = T2.id;
select T1., T2. from
(select id, type from C) T1
join
(select id, price,feedback, attribute from temp_B) T2
on T1.id = T2.id;
這樣任務的執(zhí)行速度將會有極大提升透罢!盡管看起來多了一條Hive QL榜晦,但是后兩個任務需要掃描的數據將會變得很小。
二羽圃、一次執(zhí)行多個COUNT
如果我們要對多種條件進行COUNT乾胶,可以利用case語句進行,這樣一條Hive QL就可以完成了朽寞。
select count(case when type = 1 then 1 end), count(case when type = 2 then 1 end) from table;
三识窿、導出表文件
首先需要用create table在HDFS上生成你所需要的表,當需要從HDFS上將表對應的文件導出到本地磁盤時有兩種方式:
1脑融、如果需要保持HDFS上的目錄結構喻频,原封不動地復制下來,采用下面的命令:
set hive.exec.compress.output='false';
INSERT OVERWRITE LOCAL DIRECTORY '/home/hesey/directory' select * from table;
這樣下載下來的目錄中會有很多由Reducer產生的part-文件肘迎。
2甥温、如果想把表的所有數據都下載到一個文件中,則采用下面的命令:
hadoop dfs -getmerge hdfs://hdpnn:9000/hesey/hive/table /home/hesey/table.txt
這樣所有文件會由Hadoop合并后下載到本地妓布,最后就只有/home/hesey/table.txt這一個文件姻蚓。
四、UDF
在Hive中很多時候都需要做一些復雜的計算或者邏輯處理匣沼,這時候Hive本身作為一個通用框架沒法很好地支持狰挡,所以有了UDF(User Defined Function)。
1、使用UDF
(a)如果是已經上傳到Hive服務器的UDF圆兵,可以直接用
create temporary function dosomething as 'net.hesey.udf.DoSomething';
聲明臨時函數跺讯,然后在下面的Hive QL中就可以調用dosomething這個方法了。
(b)如果是自己編寫的UDF殉农,需要在聲明臨時函數前再加一行:
add jar /home/hesey/foo.jar
這樣就可以把自定義的UDF加載進來刀脏,然后和(a)一樣聲明臨時函數就可以了。
2超凳、編寫UDF
編寫UDF十分簡單愈污,引入hive-exec包,繼承org.apache.hadoop.hive.ql.exec.UDF類轮傍,實現(xiàn)evaluate方法即可暂雹,方法的輸入和輸出參數類型就是當你在Hive中調用時的輸入和返回值。
例如:
public Text evaluate(final LongWritable number);
(Text和LongWritable是org.apache.hadoop.io下面的類)
這樣我們就可以定義自己的函數并方便地在Hive中調用创夜,而不需要寫一個重量級的MapReduce杭跪。
五、笛卡爾積
Hive本身是不支持笛卡爾積的驰吓,不能用select T1., T2.* from table_1, table_2這種語法涧尿。但有時候確實需要用到笛卡爾積的時候,可以用下面的語法來實現(xiàn)同樣的效果:
select T1., T2. from
(select * from table1) T1
join
(select * from table2) T2
on 1=1;
其中on 1=1是可選的檬贰,注意在Hive的Strict模式下不能用這種語法姑廉,需要先用set hive.mapred.mode=nonstrict;設為非strict模式就可以用了。
六翁涤、join的規(guī)則
當Hive做join運算時桥言,join前面的表會被放入內存,所以在做join時葵礼,最好把小表放在前面号阿,有利于提高性能并防止OOM。
七鸳粉、排序
在SQL中排序通過ORDER by實現(xiàn)倦西,Hive中也支持這種語法,但是使用ORDER by時最終所有的數據會匯總到一個Reducer上進行排序赁严,可能使得該Reducer壓力非常大扰柠,任務長時間無法完成。
如果排序只要求保證Value有序而Key可以無序疼约,例如要統(tǒng)計每個用戶每筆的交易額從高到低排列卤档,只需要對每個用戶的交易額排序,而用戶ID本身不需要排序程剥。這種情況采用分片排序更好劝枣,語法類似于:
select user_id, amount from table distribute by user_id sort by user_id, amount
這里用到的不是ORDER by汤踏,而是distribute by和sort by,distribute by標識Map輸出時分發(fā)的Key舔腾。
這樣最后排序的時候溪胶,相同的user_id和amount在同一個Reducer上被排序,不同的user_id可以同時分別在多個Reducer上排序稳诚,相比ORDER by只能在一個Reducer上排序哗脖,速度有成倍的提升。