本文主要讲述数据写入hive表。主要有三种方法:
- Insert…Values
- Insert…Select
- Load
前期准备:已有gmall.dwd_ad_log表,且该表为分区表,dt
日期为分区。
鉴于此,我们在创建表时,需要再额外添加一个字段。
show create table dwd_ad_log
show partitions dwd_ad_log
建库与建表
create table `test`
`mid_id` string,
`user_id` string,
`version_code` string,
`version_name` string,
`lang` string,
`source` string,
`os` string,
`area` string,
`model` string,
`brand` string,
`sdk_version` string,
`gmail` string,
`height_width` string,
`app_time` string,
`network` string,
`lng` string,
`lat` string,
`entry` string,
`action` string,
`content` string,
`detail` string,
`ad_source` string,
`behavior` string,
`newstype` string,
`show_style` string,
`server_time` string,
`id` string)
row format delimited fields terminated by ','
stored as textfile;
使用 insert into…select写入数据
insert into test select * from dwd_ad_log
对于 select 一些聚合操作等,just shift it out in a subquery:
select a from(
select a, avg(b) as avgb from asm group by a) as t
order by avgb;
该方法在生产环境中较常用,也是最容易产生小文件的情况。
使用 insert into…values写入数据
insert into table test values(),(),();
使用 load 写入数据
load data local inpath 'hdfs://192.168.184.131:9000/warehouse/gmall/dwd/dwd_ad_log/xxx.txt' into table test;
注意:若txt中包含有中文,需要确保文件格式为utf-8,否则乱码。
注:若发现使用load语句写入数据比insert语句快很多倍,这是因为hive并不对scheme进行校验,仅仅是将数据文件挪到hdfs系统上,也没有执行MR作业,因此从导入数据的角度而言,使用load要优于使用insert into…values。
表中数据写入指定路径
// 数据以csv格式写至本地路径
insert into/overwrite local directory '/test' row format delimited fields terminated by ',' select * from dwd_ad_log;
// 数据以csv格式写入hdfs
insert into/overwrite directory '/test' row format delimited fields terminated by ',' select * from dwd_ad_log;
合并小文件
小文件过多产生的影响
-1. 对底层HDFS而言,HDFS本省不适合存储大量小文件,小文件过多会导致namenode元数据特别大,占用太多内存,严重影响hdfs的性能。
-2. 对hive而言,在进行查询时,每个小文件都会当成一个块,启动一个Map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理时间,就会造成很大的资源浪费,而且,同时可执行的map数量是受限的。
concatenate
建表时,默认的文件类型为TextFile。
hive 提供了一个 alter table xxx CONCATENATE语句,用于合并小文件,但仅支持RCFILE和ORC文件类型。
create table xxx() stored as RCFile;
alter table xxx concatenate; // 可多次使用
当多次使用concatenate后文件数量不再变化,这个与参数mapreduce.input.fileinputformat.split.minsize=256mb 的设置有关,可设定每个文件的最小size。
partition 分区
表具有分区partition。
create table xxx() partitioned by `dt` row format delimited fields terminated by ','
// 将dt相同的数据放在同一个reduce处理
insert overwrite table xxx partition(dt) select * from aaa distribute by dt;
// 均匀分配 该SQL生产的文件数量为reduce个数 * 分区个数
set hive.exec.reducers.bytes.per.reducer=5120000000;
insert overwrite table xxx partition(dt) select * from aaa distribute by rand();
调整参数减少map数量
设置map输入合并小文件的相关参数
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
// 每个map最大输入大小 决定了合并后文件的数量
set mapred.max.split.size=256000000
// 一个节点上split的大小(至少) 决定了多个DataNode上的文件是否需要合并
set mapred.min.split.size.per.node=100000000
// 一个交换机下split的最小大小 决定了多个交互及上的文件是否需要合并
set maored.min.split.size.per.rack=100000000
设置map输出和reduce输出进行合并的相关参数
// 设置map端输出进行合并 默认为true
set hive.merge.mapfiles=true
// 设置reduce端输出进行合并 默认为false
set hive.merge.mapredfiles=true
// 设置合并文件的大小
set hive.merge.size.per.task=256*1000*1000
// 当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge
set hive.merge.smallfiles.avgsize=160000000
启用压缩
// hive查询结果输出是否进行压缩
set hive.exec.compress.output=true
// MapReduce job的结果输出是否使用压缩
set mapreduce.output.fileoutputformat.compress=true
减少reduce的数量
reduce 的个数决定了输出文件个数,所以可以调节reduce的个数控制hive表的文件数量,hive中的分区函数 distribute by 正好控制MR中partition分区的,然后通过设置reduce的数量,结合分区函数让数据均衡的进入每个reduce即可。
set mapreduce.job.reduces = 10
set hive.exec.reducers.bytes.per.reducer=5120000000
set mapreduce.job.reduces=10
insert overwrite table a partition(dt) select * from B distribute by rand()
使用hadoop的archive将小文件归档
hadoop archive简称 HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。
set hive.archive.enabled=true
set hive.archive.har.parentdir.settable=true
// 使用以下命令进行归档
alter table A archive partition(dt='2020-12-24',hr='12')
// 对已归档的分区恢复为原文件
alter table A unarchive partition(dt='2020-12-24',hr='12')
hive的map数和reduce数如何确定
RCFile和ORCFile
存储结构上
RCFile文件格式是FaceBook开源的一种Hive的文件存储格式,首先将表分为几个行组,对每个行组内的数据进行按列存储,每一列的数据都是分开存储,正是先水平划分,再垂直划分的理念。 在一般的行存储中,会将不同的列分开存储,这样在查询时会跳过某些列,但有时候存在一个表的有些列不再一个hdfs块上,所以在查询时,hive重组列的过程会浪费很多IO开销。而RCFile由于相同的列都是在一个HDFS块上,因此相对列存储而言会省很多资源。
存储空间上
RCFile采用游程编码,相同的数据不会重复存储,很大程度上节约了存储空间,尤其是字段中包含大量重复数据的时候。
懒加载
数据存储到表中都是压缩的数据,hive读取数据时会对其进行解压缩,但会针对特定的查询跳过不需要的列,这样也就省去了无用的列解压。