1. 程式人生 > >Hive檔案儲存格式 :Parquet sparksql ,impala的殺手鐗

Hive檔案儲存格式 :Parquet sparksql ,impala的殺手鐗

hive表的原始檔儲存格式有幾類:

1、TEXTFILE  
預設格式,建表時不指定預設為這個格式,儲存方式:行儲存
匯入資料時會直接把資料檔案拷貝到hdfs上不進行處理。原始檔可以直接通過hadoop fs -cat 檢視
磁碟開銷大 資料解析開銷大,壓縮的text檔案 hive無法進行合併和拆分


2、SEQUENCEFILE  一種Hadoop API提供的二進位制檔案,使用方便、可分割、可壓縮等特點。
SEQUENCEFILE將資料以<key,value>的形式序列化到檔案中。序列化和反序列化使用Hadoop 的標準的Writable 介面實現,優勢是檔案和Hadoop api中的mapfile是相互相容的。。
key為空,用value 存放實際的值, 這樣可以避免map 階段的排序過程。
三種壓縮選擇:NONE, RECORD, BLOCK。 Record壓縮率低,一般建議使用BLOCK壓縮。使用時設定引數,
SET hive.exec.compress.output=true;
SET io.seqfile.compression.type=BLOCK; -- NONE/RECORD/BLOCK
create table test2(str STRING)  STORED AS SEQUENCEFILE; 


3、RCFILE  
一種行列儲存相結合的儲存方式。
首先,其將資料按行分塊,保證同一個record在一個塊上,避免讀一個記錄需要讀取多個block。
其次,塊資料列式儲存,有利於資料壓縮和快速的列存取。
理論上具有高查詢效率(但hive官方說效果不明顯,只有儲存上能省10%的空間,所以不好用,可以不用)。
RCFile結合行儲存查詢的快速和列儲存節省空間的特點
1)同一行的資料位於同一節點,因此元組重構的開銷很低;
2) 塊內列儲存,可以進行列維度的資料壓縮,跳過不必要的列讀取。
查詢過程中,在IO上跳過不關心的列。實際過程是,在map階段從遠端拷貝仍然拷貝整個資料塊到本地目錄,
也並不是真正直接跳過列,而是通過掃描每一個row group的頭部定義來實現的。
但是在整個HDFS Block 級別的頭部並沒有定義每個列從哪個row group起始到哪個row group結束。
所以在讀取所有列的情況下,RCFile的效能反而沒有SequenceFile高。
讀記錄儘量涉及到的block最少
讀取需要的列只需要讀取每個row group 的頭部定義。
讀取全量資料的操作 效能可能比sequencefile沒有明顯的優勢


4、ORC格式 hive給出的新格式,屬於RCFILE的升級版,效能有大幅度提升,而且資料可以壓縮儲存,壓縮快 快速列存取
壓縮比和Lzo壓縮差不多,比text檔案壓縮比可以達到80%的空間。而且讀效能非常高,可以實現高效查詢。
一個ORC檔案包含一個或多個stripes(groups of row data),每個stripe中包含了每個column的min/max值的索引資料,當查詢中有<,>,=的操作時,
會根據min/max值,跳過掃描不包含的stripes。

具體介紹https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC  
5、自定義格式 使用者的資料檔案格式不能被當前 Hive 所識別的,時通過實現inputformat和outputformat來自定義輸入輸出格式,
參考程式碼:.\hive-0.8.1\src\contrib\src\java\org\apache\hadoop\hive\contrib\fileformat\base64  
對前集中的介紹和建表語句參見:http://www.cnblogs.com/ggjucheng/archive/2013/01/03/2843318.html

注意: 
只有TEXTFILE表能直接載入資料,必須,本地load資料,和external外部表直接載入運路徑資料,都只能用TEXTFILE表。  更深一步,hive預設支援的壓縮檔案(hadoop預設支援的壓縮格式),也只能用TEXTFILE表直接讀取。
其他格式不行。可以通過TEXTFILE表載入後insert到其他表中。  換句話說,SequenceFile、RCFile表不能直接載入資料,資料要先匯入到textfile表,再從textfile表通過insert select from 匯入到SequenceFile,RCFile表。 
SequenceFile、RCFile表的原始檔不能直接檢視,在hive中用select看。
RCFile原始檔可以用 hive --service rcfilecat /xxxxxxxxxxxxxxxxxxxxxxxxxxx/000000_0檢視,但是格式不同,很亂。
hive預設支援壓縮檔案格式參考http://blog.csdn.net/longshenlmj/article/details/50550580建表語句如下:  同時,將ORC的表中的NULL取值,由預設的\N改為'',

方式一create table if not exists test_orc(  advertiser_id string,  ad_plan_id string,  cnt BIGINT) partitioned by (day string, type TINYINT COMMENT '0 as bid, 1 as win, 2 as ck', hour TINYINT)STORED AS ORC;alter table test_orc set serdeproperties('serialization.null.format' = '');

檢視結果
hive> show create table test_orc;CREATE  TABLE `test_orc`(  `advertiser_id` string,   `ad_plan_id` string,   `cnt` bigint)PARTITIONED BY (   `day` string,   `type` tinyint COMMENT '0 as bid, 1 as win, 2 as ck',   `hour` tinyint)ROW FORMAT DELIMITED   NULL DEFINED AS '' STORED AS INPUTFORMAT   'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat' OUTPUTFORMAT   'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'LOCATION  'hdfs://namenode/hivedata/warehouse/pmp.db/test_orc'TBLPROPERTIES (  'last_modified_by'='pmp_bi',   'last_modified_time'='1465992624',   'transient_lastDdlTime'='1465992624') 

方式二 
drop table test_orc;
create table if not exists test_orc(  advertiser_id string,  ad_plan_id string,  cnt BIGINT) partitioned by (day string, type TINYINT COMMENT '0 as bid, 1 as win, 2 as ck', hour TINYINT)ROW FORMAT SERDE   'org.apache.hadoop.hive.ql.io.orc.OrcSerde' with serdeproperties('serialization.null.format' = '')STORED AS ORC;

檢視結果
hive> show create table test_orc;CREATE  TABLE `test_orc`(  `advertiser_id` string,   `ad_plan_id` string,   `cnt` bigint)PARTITIONED BY (   `day` string,   `type` tinyint COMMENT '0 as bid, 1 as win, 2 as ck',   `hour` tinyint)ROW FORMAT DELIMITED   NULL DEFINED AS '' STORED AS INPUTFORMAT   'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat' OUTPUTFORMAT   'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'LOCATION  'hdfs://namenode/hivedata/warehouse/pmp.db/test_orc'TBLPROPERTIES (  'transient_lastDdlTime'='1465992726') 

方式三
drop table test_orc;
create table if not exists test_orc(  advertiser_id string,  ad_plan_id string,  cnt BIGINT) partitioned by (day string, type TINYINT COMMENT '0 as bid, 1 as win, 2 as ck', hour TINYINT)ROW FORMAT DELIMITED   NULL DEFINED AS '' STORED AS ORC;

檢視結果
hive> show create table test_orc;CREATE  TABLE `test_orc`(  `advertiser_id` string,   `ad_plan_id` string,   `cnt` bigint)PARTITIONED BY (   `day` string,   `type` tinyint COMMENT '0 as bid, 1 as win, 2 as ck',   `hour` tinyint)ROW FORMAT DELIMITED   NULL DEFINED AS '' STORED AS INPUTFORMAT   'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat' OUTPUTFORMAT   'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'LOCATION  'hdfs://namenode/hivedata/warehouse/pmp.db/test_orc'TBLPROPERTIES (  'transient_lastDdlTime'='1465992916')
具體儲存對比,下面的資料只有單列值
> desc tmp_store ;
OK
col_name        data_type       comment
c                       string              // 只有一列值 而且包含中英文內容                        
Time taken: 0.076 seconds, Fetched: 1 row(s)

1.  TextInputFormat
CREATE TABLE `tmp_store`(
`c` string)
ROW FORMAT SERDE 
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' 
STORED AS INPUTFORMAT 
'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat';
> dfs -du -s -h  /user/hive/warehouse/test.db/tmp_store ;
753.9 M  2.2 G  /user/hive/warehouse/test.db/tmp_store ;


=========================================================
準備100萬條資料 tmp_store 
create table tmp_store_seq like tmp_store;
insert into tmp_store_seq as select * from tmp_store;

create table tmp_store_par like tmp_store_seq stored as Parquet;
insert into table tmp_store_par  select * from tmp_store_seq;

create table tmp_store_rc like tmp_store_seq stored as RCFile ;
insert into table tmp_store_rc  select * from tmp_store_seq;

create table tmp_store_orc like tmp_store_seq stored as ORC ;
insert into table tmp_store_orc select * from tmp_store_seq;


hive (test)> dfs -du -s -h /user/hive/warehouse/test.db/tmp_store ;
125.9 M  377.7 M  /user/hive/warehouse/test.db/tmp_store
hive (test)> dfs -du -s -h /user/hive/warehouse/test.db/tmp_store_orc ; 
20.1 M  60.3 M  /user/hive/warehouse/test.db/tmp_store_orc
hive (test)> dfs -du -s -h /user/hive/warehouse/test.db/tmp_store_rc ; 
101.1 M  303.3 M  /user/hive/warehouse/test.db/tmp_store_rc
hive (test)> dfs -du -s -h /user/hive/warehouse/test.db/tmp_store_par ; 
53.6 M  160.9 M  /user/hive/warehouse/test.db/tmp_store_par
hive (test)> dfs -du -s -h /user/hive/warehouse/test.db/tmp_store_seq  ; 
125.9 M  377.7 M  /user/hive/warehouse/test.db/tmp_store_seq

table		store format	size /repsize		store efficience(參照textfile)
tmp_store_orc   orc		20.1 M  60.3 M		6.26
tmp_store_par	parquet		53.6 M  160.9 M		2.35 (spark default output format)
tmp_store_rc	rcfile		101.1 M  303.3 M	1.24
tmp_store_seq	sequencefile	125.9 M  377.7 M	1
tmp_store	textfile	125.9 M  377.7 M	1 (hive default store format)

表1
sparksql 處理 |947482003|記錄時間 

tablename	store format	size /repsize		store efficience(參照textfile)	count cost time
							(first /second) (s)	
gps_log_par	parquet		47.0 G  140.9 G		2.23				28s	3s
gps_log_orc	orc		15.3 G  45.8 G		6.87				45s	25s
gps_log		textfile	104.8 G  314.5 G	1 (hive default store format)	133s	104s


表2  
impala 對parquet的支援也是極限了 第一次count 6.55s 第二次2.30s
這也可以作為互動式查詢的一個選擇,但是嘛除了parquet 其他的效率就差遠了。
前幾次直接卡住(142s),後面試了幾次等到查出來結果,之後再次查詢挺快的(看來申請資源花費時間 )
Query: select count(*) from  gps_log_201608_201610
+-----------+
| count(*)  |
+-----------+
| 947482003 |
+-----------+
Fetched 1 row(s) in 142.54s
[10.1.16.40:21000] > select count(*) from  gps_log_201608_201610 ;    
Query: select count(*) from  gps_log_201608_201610
+-----------+
| count(*)  |
+-----------+
| 947482003 |
+-----------+
Fetched 1 row(s) in 10.27s

tool		format		option		cost time (first/second) s
sparksql	textfile	count		54s	50s
						max,min		83s	未統計
						max,min,groupby 150s	未統計

sparksql	parquet		count		4s	2s
						max min		26s	12s
						max,min,
						groupby 50s	49s
			orc			支援


impala		textfile	count		142.53s	10.27s
						max,min		20.81s	18.30s
						max,min,groupby 37.27s	37.21s

parquet		count		2.39s	2.29s
						max,min		8.87s	8.78s
						max,min,groupby	36.67s	36.67s
			orc			不支援
表3
總結:
textfile	儲存空間消耗比較大,並且壓縮的text 無法分割和合並 查詢的效率最低,可以直接儲存,載入資料的速度最高
sequencefile	儲存空間消耗最大,壓縮的檔案可以分割和合並 查詢效率高,需要通過text檔案轉化來載入
rcfile		儲存空間最小,查詢的效率最高 ,需要通過text檔案轉化來載入,載入的速度最低,由於列式儲存方式,資料載入時效能消耗較大,但是具有較好的壓縮比和查詢響應。
parquet		sparksql預設的輸出格式,由上面的表2看出parquet具有要較快的處理效率顯然犧牲點儲存(相對於orc格式)但是計算速度可以很大提升,加快響應速度,提供互動式查詢
orcfile		儲存效率,處理效率兼顧 

表3資料也表明 impala做互動式查詢效率是sparksql 的三倍左右,互動式查詢的最佳組合是impala + parquet 。
不過也要考慮的是 impala的初始化需要耗費的時間應該也要考慮在內,(不過即使初始化對parquet首次查詢的響應時間在3s 內,可見一斑)

當然壓縮格式沒有列入本次對比的範疇。

給出這些資料對於平臺的儲存格式應該有一個總體的規劃了。