压缩
压缩是调优的重要的点。
另外不一定非要用带split的压缩方式,如果前期做的比较好,每个块都分割成128M(一般是比block块小一点,比如256M就放250M),就可以不用带split的压缩了。
文件的存储格式
Hive可以支持多种格式,主要有:SEQUENCEFILE,TEXTFILE,RCFILE,ORCPARQUET。其中Hive默认的文件格式是TextFile。
设定文件格式的语句是:
CREATE TABLE tt2 (
id int,
name string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS TEXTFILE;
CREATE TABLE tt3 (
id int,
name string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS
INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat';
上面两个语句创建的表的存储格式与下面的格式是相同的
CREATE TABLE tt (
id int,
name string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
行式存储与列式存储
行式存储
一整条数据在一个block里面
优点:读取全部数据(select *)的时候,可以直接从block里面获取。
缺点:每个字段的类型可能不同,比如:有int,string,date,boolean等等,由于所有的字段存放在一起,在压缩的时候性能就不够好。
读取全部的时候直接读取,但是select id等等某些字段的时候,就需要把所有的行都读取进来,然后再找id,因为不能跳过数据,所以占用磁盘IO,花费较多的时间,导致效率不够高。
列式存储
某些列存在一个block里面(可能是两列,也可能是一列,一列就是一个字段)
优点:当读取部分列的时候,可以只读一部分block而不用全部读取。
缺点:使用select * 来查询或者查询字段比较多的时候,所有的block数据需要重组,占用IO。
对于大数据来说,大部分的表都只用部分字段。
存储格式比较
TextFile
默认文本类型,解析起来比较麻烦,但是通用性比较好。
SEQUENCEFILE
key-value存储,SequenceFile相比TextFile 多了一些冗余信息(头(Header),Sync什么的,用来记录key-value的长度,比如:总长10,key长4,那么读取value的时候就可以直接读取另外6个),可以搜索这个存储的图片,方便理解。
对于压缩,SEQUENCEFILE压缩的地方是value(Compressed value)
优点是随机读写性能好一些,因为可以跳过一些地方直接读value
Hive创建了一个存储格式为SEQUENCEFILE的表,那么在导入数据的时候就不能直接从本地导入TextFile(文本文件)格式的文件,可以通过导入一个同样schema的中间表(TextFile)来过渡。
CREATE TABLE tt_rcfile (
id int,
name string
) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS SEQUENCEFILE;
insert into table tt4 select * from tt;
RCFILE
Record(记录) Columnar(列式) File,是一个列式存储的格式。
其实只能提升10%的存储(大小减少10%),而且是行列混合的(可以上网上搜图),先是行式存储成row group,然后在里面按列存储
ORC
会对数据做索引,当查询语句含有一定条件的时候,就可能会跳过一些数据,从而减少IO。https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC
create table tt_orc
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS ORC
TBLPROPERTIES("orc.compress"="NONE")
as select * from tt;
create table tt_orc_zlib
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS ORC
TBLPROPERTIES("orc.compress"="ZLIB")
as select * from tt;
即设置了存储格式又设置了压缩。(压缩默认是zlib)
将原大小18.1M的文本文件变为7.7M(没使用压缩),2.8M(zlib压缩)。
PARQUET
https://cwiki.apache.org/confluwnce/display/Hive/Parquet
使用这个存储格式,可以将原大小18.1M的文本文件变为13.1M(没有使用压缩),自己定义压缩(gzip,snappy等等):
set parquet.compression=gzip;
create table tt_parquet_gzip
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t"
STORED AS PARQUET
as select * from tt;
压缩后文件大小为3.9M
对比
数据量小,对比不出来时间上的差距,可以查看MapReduce运行完成后读取的数据量:
select count(1) from tt where id='B58W48U4WKZCJ5D1T3Z9ZY88RU7QA7B1';
HDFS Read:19022700(MapReduce执行完毕后会在后几行显示出来这个信息)
select count(1) from tt_rcfile where id='B58W48U4WKZCJ5D1T3Z9ZY88RU7QA7B1';
3725391
select count(1) from tt_orc where id='B58W48U4WKZCJ5D1T3Z9ZY88RU7QA7B1';
1810082
select count(1) from tt_orc_zlib where id='B58W48U4WKZCJ5D1T3Z9ZY88RU7QA7B1';
1257539
select count(1) from tt_parquet where id='B58W48U4WKZCJ5D1T3Z9ZY88RU7QA7B1';
2687025
select count(1) from tt_parquet_gzip where id='B58W48U4WKZCJ5D1T3Z9ZY88RU7QA7B1';
1624507
ORC查询数据量少的原因是因为predicate pushdown (谓词下压)。
所以,做好的组合是:
ORC/PARQUET + COMPRESSION(orc或者parquet格式,再加上压缩)