HDFS非常容易存储大数据文件,如果Hive中存在过多的小文件会给namecode带来巨大的性能压力。同时小文件过多会影响JOB的执行,hadoop会将一个job转换成多个task,即使对于每个小文件也需要一个task去单独处理,task作为一个独立的jvm实例,其开启和停止的开销可能会大大超过实际的任务处理时间。
同时我们知道hive输出最终是mr的输出,即reducer(或mapper)的输出,有多少个reducer(mapper)输出就会生成多少个输出文件,根据shuffle/sort的原理,每个文件按照某个值进行shuffle后的结果。
为了防止生成过多小文件,hive可以通过配置参数在mr过程中合并小文件。而且在执行sql之前将小文件都进行Merge,也会提高程序的性能。我们可以从两个方面进行优化,其一是map执行之前将小文件进行合并会提高性能,其二是输出的时候进行合并压缩,减少IO压力。
一、hive参数优化
Map操作之前合并小文件:
#每个Map最大输入大小设置为2GB(单位:字节)
set mapred.max.split.size=2147483648
set hive.hadoop.supports.splittable.combineinputformat=true;
#执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
输出时进行合并:
#在Map-only的任务结束时合并小文件。是否和并 Map输出文件,默认为 True,
set hive.merge.mapfiles = true
#在Map-Reduce的任务结束时合并小文件
set hive.merge.mapredfiles= true
#合并后MR输出文件的大小为1GB
set hive.merge.size.per.task = 1073741824
#当输出文件的平均大小小于1GB时,启动一个独立的map-reduce任务进行文件merge
set hive.merge.smallfiles.avgsize=1073741824
二、文件压缩
set hive.exec.compress.output=true;
#默认false,是否对输出结果压缩
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;
#具体的压缩算法的配置参数,要使用的压缩编码/解码器的类名。
set mapred.output.compression.type=BLOCK;
sequencefile有三种压缩方式:NONE, RECORD, BLOCK。默认是启用RECORD级(压缩单独的记录)的压缩的,这种方式的压缩率是非常低的。BLOCK(压缩一组记录)压缩率最高,一般用BLOCK。
set mapred.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;
SnappyCodec比较适合在这种场景中编解码器,该算法会带来很好的压缩性能和较低的CPU开销
1、Hive中间数据压缩Lzo,最终数据压缩Gzip
set mapred.compress.map.output = true;
set mapred.map.output.compression.codec = org.apache.hadoop.io.compress.LzoCodec;
set mapred.output.compress = true;
set mapred.output.compression.codec = org.apache.hadoop.io.compress.GzipCodec;
set mapred.output.compression.type = BLOCK;
set hive.exec.compress.intermediate = true; #启用中间数据压缩
set hive.intermediate.compression.codec = org.apache.hadoop.io.compress.LzoCodec;
set hive.exec.compress.output = true;
三、文件存储
hive在创建表时默认存储格式是textfile,或者显示自定义的stored as textfile.hive常用的存储格式有三种,textfile,sequencefile,rcfile。
为什么hive会有多种存储格式?因为hive是文本批处理系统,所以就存在一个往hive中导入数据的问题,首先数据的存储格式有多种,比如数据源是二进制格式, 普通文本格式等等,而hive强大之处不要求数据转换成特定的格式,而是利用hadoop本身InputFormat API来从不同的数据源读取数据,同样地使用OutputFormat API将数据写成不同的格式。所以对于不同的数据源,或者写出不同的格式就需要不同的对应的InputFormat和Outputformat类的实现。
以stored as textfile(其实这就是下面stored as inputformat -outputformat的缩减写法)为例,其在底层java API中表现是输入InputFormat格式:TextInputFormat以及输出OutputFormat格式:HiveIgnoreKeyTextOutputFormat.这里InputFormat中定义了如何对数据源文本进行读取划分,以及如何将切片分割成记录存入表中。而Outputformat定义了如何将这些切片写回到文件里或者直接在控制台输出。
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
实际上hive使用一个TextInputFormat对象将输入流分割成记录,然后使用一个HiveIgnoreKeyTextOutputFormat对象来将记录格式化为输出流(比如查询的结果),再使用Serde在读数据时将记录解析成列。在写数据时将列编码成记录。所以stored as ''只是决定了行级别(记录级别 )的存储格式,而实际将记录解析成列依靠的则是Serde对象,比如hive默认的ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' 。或者用户自定义的Serde格式。
textfile,sequencefile和rcfile的三种存储格式的本质和区别
文件存储编码格式 | 建表时如何指定 | 优点弊端 | |
textfile | 文件存储就是正常的文本格式,将表中的数据在hdfs上 以文本的格式存储 ,下载后可以直接查看,也可以使用cat命令查看 |
1.无需指定,默认就是 2.显示指定stored as textfile 3.显示指定 STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' |
1.行存储使用textfile存储文件默认每一行就是一条记录, 2.可以使用任意的分隔符进行分割。 3.但无压缩,所以造成存储空间大。可结合Gzip、Bzip2、Snappy等使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。 4、 textfile为默认格式,存储方式为行存储 |
sequencefile | 在hdfs上将表中的数据以二进制格式编码,并且将数据压缩了,下载数据 以后是二进制格式,不可以直接查看,无法可视化。 |
1.stored as sequecefile 2.或者显示指定: STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.SequenceFileInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat' |
1.sequencefile存储格有压缩,存储空间小,有利于优化磁盘和I/O性能 2.同时支持文件切割分片,提供了三种压缩方式:none,record,block(块级别压缩效率跟高).默认是record(记录) 3.基于行存储 |
rcfile | 在hdfs上将表中的数据以二进制格式编码,并且支持压缩。下载后的数据不可以直接可视化。 | 1.stored as rcfile 2.或者显示指定: STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.RCFileInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.RCFileOutputFormat' |
1.行列混合的存储格式,基于列存储。 2.因为基于列存储,列值重复多,所以压缩效率高。 3.磁盘存储空间小,io小。 4.hive/spark都支持这种存储格式,它存储的方式是采用数据按照行分块,每个块按照列存储,其中每个块都存储有一个索引。特点是数据压缩率非常高。 |
创建时可以直接指定存储格式
create table parquet(
...
)
row format delimited fields terminated by '\t'
stored as parquet;
hive中不同存储格式转换,需要使用insert ....select
磁盘空间占用大小比较(较大数据量)
orc
四、行列分隔符
CREATE TABLE `dwa_mytable`(
`msisdn` string COMMENT '手机号码',
`location` string COMMENT '位置'
)
PARTITIONED BY (
`month_id` string,
`day_id` string,
`prov_id` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
'field.delim'='|',
'serialization.format'='|')
STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
'hdfs://beh/user/hadoopvip/lf_xx_dwa.db/dwa_mytable'
TBLPROPERTIES (
'last_modified_by'='hadoopvip',
'last_modified_time'='1524300660',
'transient_lastDdlTime'='1524300600')
Time taken: 0.062 seconds, Fetched: 49 row(s)
hive默认的列分割类型为org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,而这其实就是^A分隔符,hive中默认使用^A(ctrl+A)作为列分割符,如果用户需要指定的话,等同于row format delimited fields terminated by '\001',因为^A八进制编码体现为'\001'.所以如果使用默认的分隔符,可以什么都不加,也可以按照上面的指定加‘\001’为列分隔符,效果一样。
hive默认使用的行分隔符是'\n'分隔符 ,也可以加一句:LINES TERMINATED BY '\n' ,加不加效果一样。但是区别是hive可以通过row format delimited fields terminated by '\t'这个语句来指定不同的分隔符,但是hive不能够通过LINES TERMINATED BY '$$'来指定行分隔符,目前为止,hive的默认行分隔符仅支持‘\n’字符。否则报错。
hive ()> create table fdm_sor.mytest_tm4(
> id int comment'编号',
> name string comment '名字'
> )
> lines terminated by '\t';
FAILED: ParseException line 5:1 missing EOF at 'lines' near ')'
但,可以通过自定义Inputformat和outputformat类来指定特定行分隔符和列分隔符。
文章后半部分转载:https://blog.csdn.net/qq_26442553/article/details/80300714