目录
4.4 hive job的优化——job合并输入\输出小文件
1.hive简介
1.1 什么是hive
hive是一种基于Hadoop的数据仓库工具,它可以将结构化的数据文件映射为一张数据表,并提供类sql查询功能。它可以将sql语句转换为MapReduce任务进行运行。hive主要是利用HDFS来存储数据,利用MapReduce来查询分析数据。它的本质是将sql转换成MapReduce程序,比直接用MapReduce开发效率更高。hive在运行时,实际的源数据存在HDFS上,而描述数据的元数据存放在关系型数据库中(有三种存储方式,建议存在关系型数据库中)。
1.2 hive的元数据存储
hive的元数据存储方式:
1.内存数据库 derby,安装小,但是数据存在内存,不稳定
2.mysql数据库,数据存储模式可以自己设置,持久化好,查看方便。
hive中元数据包括表的名字,表的列和分区以及属性,表的属性(是否为外部表),表的数据所在目录等。
1.3 hive与传统数据库的区别
- 查询语言。由于sql被广泛应用在数据仓库中,因此,专门针对hive的特性设计了类sql的查询语言hql。
- 数据存储位置。hive是建立在hadoop之上的,所有hive的数据都是存储在HDFS中的。而数据库则可以将数据保存在块设备或本地文件系统中。
- 数据格式。Hive中没有定义专门的数据格式,由用户指定,需要指定三个属性:列分隔符,行分隔符,以及读取文件数据的方法(hive中默认有三个文件格式textfile、sequencefile、rcfile)。数据库中,存储引擎定义了自己的数据格式。所有数据都会按照一定的组织存储。
- 数据更新。Hive的内容是读多写少的,因此,不支持对数据的改写和删除,数据都在加载的时候中确定好的。数据库中的数据通常是需要经常进行修改。
- 索引。hive在加载数据的过程中不会对数据进行任何处理,甚至不会对数据进行扫描,因此也没有对数据中某些key建立索引。由于MapReduce的引入,hive可以并行访问数据,因此即使没有索引,对于大数据量的访问,hive仍然可以体现出优势。数据库中,通常会针对一个或者几个列建立索引,因此对于少量的特定条件的数据的访问,数据库可以有很高的效率。
- 执行延迟。Hive在查询数据的时候,需要扫描整个表(或分区),因此延迟较高,只有在处理大数据是才有优势。数据库在处理小数据是执行延迟较低。
- 执行。Hive是MapReduce,数据库是Executor
- 数据规模。Hive大,数据库小。
2.hive原理
3.hive的数据管理
hive中所有的数据都存储在HDFS中,没有专门的数据存储格式。我们只需要在建表的时候告诉hive数据中的列分隔符和行分隔符,hive就可以解析数据。
3.1 hive中的内部表和外部表
内部表:未被external修饰的表。表数据由hive自身管理,表数据存储的位置是默认的hive.metastore.warehouse.dir,删除表会直接删除元数据以及存储数据、对表的修改会将修改直接同步给元数据的内部表。
create table student(sno int,sname string,sage int) row format delimited fields terminated by '\t';
外部表:被external修饰的表,表数据有hdfs管理、表数据的存储位置有自己指定、删除表仅仅删除元数据,hdfs上的文件并不会被删除。
create external table student_ext(sno int,sname string,sage int) row format delimited fields terminated by '\t' location '/stu';
生成环境中为什么建议使用外部表?
- 外部表不会加载数据到hive的hdfs目录,减少数据传输,数据还能共享。
- hive不会修改数据,所以不需要担心数据的损坏,删除表时只删除表结构,不会删除数据。
3.2 hive中的分区表
为了避免select查询时出现的全表扫描问题,hive提出了分区表(partitioned by),通俗讲,就是给文件归类打上标识,标识不能为表中已有的字段。
分区表又分为静态分区和动态分区。
创建静态单分区表:
create table day_table (id int,content string) partitioned by (dt string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' ;
创建静态多分区表:
create table day_hour_table (
id int,
content string
)
partitioned by (dt int,hour int) -- 按照dt,hour分区
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t' ;
静态分区表加载数据必须指定分区:
insert into day_table partition (dt = "9-26") values(1,"anb");
insert into day_hour_table partition(dt=9,hour=1) values(1,"a2 bc");
load data local inpath "/root/ceshi" into table day_table partition (dt="9-27");
load data local inpath "/root/ceshi" into table day_table partition (dt=10,hour=10);
删除分区:
ALTER TABLE day_table DROP PARTITION (dt="9-27");
ALTER TABLE day_table DROP PARTITION (dt=10,hour=10);
查询表的分区:
SHOW PARTITIONS table_name;
静态分区在插入的时候必须要知道有什么分区类型,而且每个分区写一个load data,太麻烦。动态分区可以根据查询到的数据动态分配到分区里。
创建动态分区表之前的操作
开启支持动态分区
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;默认是strict,不允许分区列全部是动态的
静态分区与动态分区创建表的语句是一模一样的
CREATE TABLE gfstbl_dynamic(
id INT,
name STRING,
gfs ARRAY<STRING>,
address MAP<STRING,STRING>,
info STRUCT<country:String,province:String,shi:String>
)
partitioned by (sex string,age INT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ' '
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':'
LINES TERMINATED BY '\n';
动态分区表加载数据:(不可以使用load,它只是将数据上传到HDFS指定目录中,而动态分区是自动分区的)
from gfstbl_pt
insert into gfstbl_dynamic partition(sex,age)
select id,name,gfs,address,info,sex,age;
查看分区数:
show partitions gfstbl_dynamic;
3.3 hive中的分桶表
为了提高join查询时的效率,减少笛卡尔积的数量,出现了分桶表。分桶表是对数据进行哈希取值,然后放到不同文件中存储。
之前要开启分桶表的支持:set hive.enforce.bucketing=true;
创建分桶表
create table bucket_user (id int,name string)
clustered by (id) into 4 buckets
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
插入数据:
insert into table bucket_user partition(id) select id, name from original;
抽样:
select * from bucket_user tablesample(bucket x out of y on id);
y必须是table总bucket数的倍数或者因子。
x表示从哪个bucket开始抽取。
分桶数/y 指的是抽取几个桶的数据。
例如,table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据,分别为第3个bucket和第(3+16=)19个bucket的数据。
分桶+分区表
CREATE TABLE psnbucket_partition( id INT, name STRING, age INT)
PARTITIONED BY(height DOUBLE)
CLUSTERED BY (age) INTO 4 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
4.hive的调优
核心思想:把Hive SQL当作Map Reduce程序去优化
但是不是所有的SQL都会被转化为MapReduce来执行
- select仅查询本表字段。如select * from table;
- where只对本表字段做条件过滤
4.1 hive job的优化——表优化
对表进行分区处理。静态分区和动态分区,上面介绍过。
4.2 hive job的优化——并行化执行
hive执行过程中是按照默认的顺序来执行的,如果没有太大的依赖关系,最好并行执行,减少执行时间,每个查询被hive转化为多个阶段,有些阶段关联性不大,则可以并行执行,减少执行时间。
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=16;默认8
4.3 hive job的优化——本地化执行
set hive.exec.mode.local.auto=true;
当一个job满足如下条件的时候,才能真正使用本地模式。
1.job的输入数据大小必须小于参数 hive.exec.mode.local.inputbytes.max 默认为128m
2.job的map数必须小于参数 hive.exec.mode.local.auto.tasks.max 默认4
3.job的reduce数量必须为0或1.
4.4 hive job的优化——job合并输入\输出小文件
在集群中面临这样的问题,集群中很多的小文件,而且这些小文件的执行时间特别短,造成集群的资源没有好好利用。
解决
set hive.input.format=oar.apache.hadoop.hive.ql.io.CombineHiveInputFormat
这样做后,就会把多个split分片合并成一个。合并的文件数由mapred.max.split.size限制的大小决定。
4.6
4.4 hive job的优化——jvm重用
- 适用场景:
- 小文件个数过多
- task个数过多
- 通过
set mapred.job.reuse.jvm.num.tasks=n;
来设置,n为task插槽个数
4.5 hive job的优化——压缩数据
中间压缩就是处理hive查询的多个job之间的数据。减少网络传输的数据量。
4.6 hive job的优化——数据倾斜
- 操作
Join
Group by
Count Distinct
- 原因
key分布不均导致的
人为的建表疏忽
业务数据特点
- 症状
任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。查看未完成的子任务,可以看到本地读写数据量积累非常大,通常超过10GB可以认定为发生数据倾斜。
- 倾斜度
平均记录数超过50w且最大记录数是超过平均记录数的4倍。
最长时长比平均时长超过4分钟,且最大时长超过平均时长的2倍。
- 万能方法
hive.groupby.skewindata=true