Hive基本概念
什么是Hive
Hive:由Facebook开源用于解决海量结构化日志的数据统计。Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能。
本质是:将HQL转化成MapReduce程序
Hive的优缺点
- 1)操作接口采用类SQL语法,提供快速开发的能力(简单、容易上手)。
- 2)避免了去写MapReduce,减少开发人员的学习成本。
- Hive优势在于处理大数据,对于处理小数据没有优势
- 5)Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
缺点
- Hive的HQL表达能力有限
- Hive的效率比较低
- Hive调优比较困难,粒度较粗
HIve的架构原理
-
用户接口:Client(CLI)
CLI/jdbc、web等来访问hive -
元数据:
元数据包括表名、表所属的数据库、列名字段名、表的所有这等 -
HDFS、使用HDFS进行存储
-
驱动器:Driver
a 、解析器:将sql语句转换成抽象语法树,对抽象语法树做分析,比如是否含有这个语法、是否含有这个字段等
b、编译器:将ast抽象语法树转换成执行计划
c、优化器:对执行计划进行优化
e、执行器:把逻辑执行计划转换成物理执行计划。对Hive来说就是MR/Spark。
Hive和数据库的比较
由于 Hive 采用了类似SQL 的查询语言 HQL(Hive Query Language),因此很容易将 Hive 理解为数据库。其实从结构上来看,Hive 和数据库除了拥有类似的查询语言,再无类似之处。本文将从多个方面来阐述 Hive 和数据库的差异。数据库可以用在 Online 的应用中,但是Hive 是为数据仓库而设计的,清楚这一点,有助于从应用角度理解 Hive 的特性。
- 查询语言:由于SQL被广泛的应用在数据仓库中,因此,专门针对Hive的特性设计了类SQL的查询语言HQL。熟悉SQL开发的开发者可以很方便的使用Hive进行开发。
- 数据存储位置:Hive 是建立在 Hadoop 之上的,所有 Hive 的数据都是存储在 HDFS 中的。而数据库则可以将数据保存在块设备或者本地文件系统中。
- 数据更新:由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive中不建议对数据的改写,所有的数据都是在加载的时候确定好的。而数据库中的数据通常是需要经常进行修改的,因此可以使用 INSERT INTO … VALUES 添加数据,使用 UPDATE … SET修改数据。
- 执行:Hive中大多数查询的执行是通过 Hadoop 提供的 MapReduce 来实现的。而数据库通常有自己的执行引擎。
- 执行延迟:Hive 在查询数据的时候,由于没有索引,需要扫描整个表,因此延迟较高。另外一个导致 Hive 执行延迟高的因素是 MapReduce框架。由于MapReduce 本身具有较高的延迟,因此在利用MapReduce 执行Hive查询时,也会有较高的延迟。相对的,数据库的执行延迟较低。当然,这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive的并行计算显然能体现出优势。
- 可扩展性:由于Hive是建立在Hadoop之上的,因此Hive的可扩展性是和Hadoop的可扩展性是一致的(世界上最大的Hadoop 集群在 Yahoo!,2009年的规模在4000 台节点左右)。而数据库由于 ACID 语义的严格限制,扩展行非常有限。目前最先进的并行数据库 Oracle 在理论上的扩展能力也只有100台左右。
将本地文件导入Hive案例
1、在/opt/module/目录下创建datas
2、在/opt/module/datas/目录下创建student.txt文件并添加数据
[atguigu@hadoop102 datas]$ touch student.txt
[atguigu@hadoop102 datas]$ vi student.txt
1001 zhangshan
1002 lishi
1003 zhaoliu
3、Hive实际操作:首先启动hive:
bin/hive
2、创建student表, 并声明文件分隔符’\t’
creat table student (id int,name string)row format delimited fiels terminated by '\t'
3、加载/opt/module/datas/student.txt 文件到student数据库表中。
load data local inpath '/opt/module/datas/student.txt' into table student;
Hive查询结果
hive> select * from student;
OK
1001 zhangshan
1002 lishi
1003 zhaoliu
Time taken: 0.266 seconds, Fetched: 3 row(s)
Hive常用交互命令
- “-e”不进入hive的交互窗口执行sql语句:
[atguigu@hadoop102 hive]$ bin/hive -e "select id from student;"
2、-f”执行脚本中sql语句
[atguigu@hadoop102 datas]$ touch hivef.sql
atguigu@hadoop102 hive]$ bin/hive -f /opt/module/datas/hivef.sql
[atguigu@hadoop102 hive]$ bin/hive -f /opt/module/datas/hivef.sql > /opt/module/datas/hive_result.txt
3、退出hive窗口:exit:先隐性提交数据,再退出;quit:不提交数据,退出;
4、在hive cli命令窗口中如何查看hdfs文件系统:dfs -ls /;
5、在hive cli命令窗口中如何查看本地文件系统 !ls /opt/module
Hive的数据类型
集合数据类型:
创建表语句
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...)
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]
字段解释说明 :
(1)CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。
(2)EXTERNAL关键字可以让用户创建一个外部表,在建表的同时可以指定一个指向实际数据的路径(LOCATION),在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。
(3)COMMENT:为表和列添加注释。
(4)PARTITIONED BY创建分区表
(5)CLUSTERED BY创建分桶表
(6)SORTED BY不常用,对桶中的一个或多个列另外排序
(7)ROW FORMAT
(8)STORED AS指定存储文件类型:常用的存储文件类型:SEQUENCEFILE(二进制序列文件)、TEXTFILE(文本)、RCFILE(列式存储格式文件)
(9)LOCATION :指定表在HDFS上的存储位置。
(10)AS:后跟查询语句,根据查询结果创建表。
(11)LIKE允许用户复制现有的表结构,但是不复制数据。
一些命令举例:
(1)普通创建表:
create table if not exists student2(
id int, name string
)
row format delimited fields terminated by '\t'
stored as textfile
location '/user/hive/warehouse/student2';
(2)根据查询结果创建表(查询的结果会添加到新创建的表中)
create table if not exists student3 as select id, name from student;
(3)根据已经存在的表结构创建表
create table if not exists student4 like student;
(4)创建外部表:
hive (default)> create external table stu_external(
id int,
name string)
row format delimited fields terminated by '\t'
location '/student';
管理表与外部表的互相转换:
转外部表:
alter table student2 set tblproperties('EXTERNAL'='TRUE');
转内部表:
alter table student2 set tblproperties('EXTERNAL'='FALSE');
分区表
分区表实际上就是对应一个HDFS文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。Hive中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过WHERE子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。
创建分区表
hive (default)> create table dept_partition(
deptno int, dname string, loc string
)
partitioned by (month string)
row format delimited fields terminated by '\t';
注意:分区字段不能是表中已经存在的数据,可以将分区字段看作表的伪列
加载数据到分区表中:
hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201709');
hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201708');
hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201707’);
注意:分区表加载数据时,必须指定分区
查询分区表中数据:
单分区表查询:
hive (default)> select * from dept_partition where month='201709';
多分区联合查询:
select * from dept_partition where month='201709'
union
select * from dept_partition where month='201708'
union
select * from dept_partition where month='201707';
增加分区:
增加单个分区:
alter table x add partition (month='202002');
增加多个分区:
alter table x add partition (month='123456') partition (month='456789');
删除单个分区:
alter table x drop partition (month='12346')
删除多个分区:
alter table xx drop partition (month='1236'),partition(month='123456')
创建二级分区表:
create table dept_partition2(
deptno int, dname string, loc string
)
partitioned by (month string, day string)
row format delimited fields terminated by '\t';
加载数据到二级分区表中:
load data local inpath '/opt/module/datas/dept.txt' into table
default.dept_partition2 partition(month='201709', day='13');
查询分区数据:
hive (default)> select * from dept_partition2 where month='201709' and day='13';
把数据直接上传到分区目录上,让分区表和数据产生关联的三种方式:
- 先上传数据然后修复数据库:
上传数据
hive (default)> dfs -mkdir -p
/user/hive/warehouse/dept_partition2/month=201709/day=12;
hive (default)> dfs -put /opt/module/datas/dept.txt /user/hive/warehouse/dept_partition2/month=201709/day=12;
查询数据(查询不到刚上传的数据)
执行修复命令
msck repair table dept_partition2;
再次查询数据ok了
2、上传数据后添加分区:
上传数据:
执行添加分区:
hive (default)> alter table dept_partition2 add partition(month='201709',
day='11');
3、创建文件夹后load数据到分区
创建目录:
hive (default)> dfs -mkdir -p
/user/hive/warehouse/dept_partition2/month=201709/day=10;
上传数据:
hive (default)> load data local inpath '/opt/module/datas/dept.txt' into table
dept_partition2 partition(month='201709',day='10');
数据导入
向表中装载数据(Load)
语法:
load data [local] inpath '/opt/software' into table stu [partition(partcol1=val1,...)]
加载HDFS文件到hive中:
load data inpath '/user/data' into table stu partition(partcol1=val1)
通过查询语句向表中插入数据(Insert)
创建表:
create table stu(id int,name string) partitioned by(month string) row format delimited fields terminated by '/t'
基本插入数据语法:
instert into table stu partition(month='2020') values (1,'doudou')
基本模式插入(根据单张表查询结果):
insert into table stu partition(month='2020')select * from stu2 where month='2020';
insert overwrite table stu partition(month='2020')select * from stu2 where month='2020'
insert into 代表追加的方式添加,而overwrite是以覆盖的方式添加。
查询语句中创建表并加载数据(As Select)
注意要和上面的根据查询插入数据库做出分别,上面的是先创建表,之后在插入查询而且查询的时候不添加as select,而查询语句中创建表:
create table if not exit stu as select * from stu2 where month='2020';
创建表时通过Location指定加载数据路径
hive (default)> create external table if not exists student5(
id int, name string
)
row format delimited fields terminated by '\t'
location '/student;
数据的导入导出
数据的导入
注意:先用export导出后,再将数据导入
import table stu where month='2020' from '/opt/soft/stu'
数据导出
- Insert导出:
insert overwrite local directory '/opt/soft' select * from stu where month='2020'
将查询的结果格式化导出到本地:
insert overwrite local directory '/opt/soft' row format delimeted fields terminated by '/t' select * from stu;
将查询的结果导出到HDFS上(没有local):
insert into directory '/user/tmp' row format delimated fields terminated by '/t' select * from stu2;
Hadoop命令导出到本地
hive (default)> dfs -get /user/hive/warehouse/student/month=201709/000000_0
/opt/module/datas/export/student3.txt;
Hive Shell 命令导出
[atguigu@hadoop102 hive]$ bin/hive -e 'select * from default.student;' >
/opt/module/datas/export/student4.txt;
Export 导出到HDFS上:
export table default.student to
'/user/hive/warehouse/export/student';
清除表中数据(Truncate)
truncate table stu
Having语句
having只和使用分组Group by一起使用替代where
HIVE的join操作:
大多数情况下,Hive会对每对JOIN连接对象启动一个MapReduce任务。本例中会首先启动一个MapReduce job对表e和表d进行连接操作,然后会再启动一个MapReduce job将第一个MapReduce job的输出和表l;进行连接操作。注意:为什么不是表d和表l先进行连接操作呢?这是因为Hive总是按照从左到右的顺序执行的。
优化:当对3个或者更多表进行join连接时,如果每个on子句都使用相同的连接键的话,那么只会产生一个MapReduce job。
Hive的排序
-
全排序:就是我们熟悉的sql里的order by用法和其一致
-
每个MapReduce内部排序(Sort By):若要进行部分排序需要如下步骤
sort by排序不分区只是按照reduce的个数生成相应数量文件夹在其中排序
a、设置reduce的个数:set mapReduce.job.reduces=3
b、select * from stu sort by desc; -
分区排序(Distribute By):就是先按照distribute by分区然后在按照sort by 进行排序:Distribute By: 在有些情况下,我们需要控制某个特定行应该到哪个reducer,通常是为了进行后续的聚集操作。distribute by 子句可以做这件事。distribute by类似MR中partition(自定义分区),进行分区,结合sort by使用。
a、同样的要先设置MapReduce的reduce个数
b、insert overwrite local directory ‘/opt/soft’ select * from stu distribute by stu.id sort by stu.old;
distibute by 是按照给定字段的hash值然后同reduce的个数取%操作进行分区,然后在按照sort by后面的条件进行排序。 -
Cluster By:这种排序是当distribute by和sort by的字段相同时候可以用这个替代,但是不能指定升序还是降序。
以下两种写法等价:
hive (default)> select * from emp cluster by deptno;
hive (default)> select * from emp distribute by deptno sort by deptno;
分桶及抽样查询
分区是对原数据的一种隔离和优化查询的方式,不过并非所有数据都可以分区。对于一张表或者一个分区来说,其可以更细粒度的进行分桶,
分区是针对文件夹的,分桶是针对数据文件
先创建分桶表,通过直接导入数据文件的方式
create table stu(id int,name string)
clustered by(id) into 4 buckets
row format delimated fields terminated by '\t';
此时我们利用load导入数据后发现并没有分桶,是因为分桶的表导入数据要通过子查询的方式:
1、 先构建一张普通的表:
create table stu(id int, name string)
row format delimited fields terminated by '\t';
2、向普通的stu表中导入数据:
load data local inpath '/opt/module/datas/student.txt' into table stu;
3、清空stu_buck表中数据
truncate table stu_buck;
select * from stu_buck;
4、需要设置一个属性:
hive (default)> set hive.enforce.bucketing=true;
hive (default)> set mapreduce.job.reduces=-1;
5、导入数据到分桶表,通过子查询的方式
insert into table stu_buck
select id, name from stu;
分桶抽样查询
对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。Hive可以通过对表进行抽样来满足这个需求。
select * from stu tablesample(bucket x out of y )
其中的y因子为抽样的大小,其值必须为总桶量的整数倍或因子,例如:一共分了4个桶,那么y为2的时候我们抽取的大小为4/2=2即抽取两个桶的数据,而当y=8的时候那么就是4/,8=0.5个桶的数据。
x表示从哪个桶开始抽取如果需要抽取多个分区那么就是当前分区号加上y,
注意
:x的值必须小于等于y的值,否则
FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause for table stu_buck
其他常用查询函数
空字段赋值:NVL函数格式为NVL(value,default_value)即当查到的值为value那么我们就替换为default_value,这个可以用来将null置换为一个默认值。
行转列
介绍三个函数:
CONCAT函数就是拼接字符串用指定的字符例如concat(1,‘’,‘’,2)=》1,2
CONCAT_WS就是用指定的字符拼接字符串例如: concat_ws(’|’, collect_set(t1.name)) 注意其第二个参数而集合
COLLECT_SET就是接受一列去重汇总。
行转列实例:
例如将上面数据转换成:
语句如下:
select
t1.base,
concat_ws('|', collect_set(t1.name)) name
from
(select
name,
concat(constellation, ",", blood_type) base
from
person_info) t1
group by
t1.base;
列转行
1.函数说明:
EXPLODE(col):将hive一列中复杂的array或者map结构拆分成多行。
LATERAL VIEW:LATERAL VIEW udtf(expression) tableAlias AS columnAlias,解释:用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合
举例:
数据准备:
需求:
select
movie,
category_name
from
movie_info lateral view explode(category) table_tmp as category_name;
Rank:
RANK() 排序相同时会重复,总数不会变
DENSE_RANK() 排序相同时会重复,总数会减少
ROW_NUMBER() 会根据顺序计算
计算每门学科成绩排名。:
select name,
subject,
score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rmp
from score;
函数
自定义函数:
当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数(UDF:user-defined function)。
根据用户自定义函数类别分为以下三种:
1)UDF(User-Defined-Function)
一进一出
(2)UDAF(User-Defined Aggregation Function)
聚集函数,多进一出
类似于:count/max/min
(3)UDTF(User-Defined Table-Generating Functions)
一进多出
举例UDF:
- 创建一个Maven工程Hive
- 导入依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.hive/hive-exec -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
</dependencies>
3、创建一个类
package com.atguigu.hive;
import org.apache.hadoop.hive.ql.exec.UDF;
public class Lower extends UDF {
public String evaluate (final String s) {
if (s == null) {
return null;
}
return s.toLowerCase();
}
}
4、打成jar包上传到服务器/opt/module/jars/udf.jar
5、将jar包添加到hive的classpath
hive (default)> add jar /opt/module/datas/udf.jar;
6、创建临时函数与开发好的java class关联
hive (default)> create temporary function mylower as "com.atguigu.hive.Lower";
7、即可在hql中使用自定义的函数strip
ive (default)> select ename, mylower(ename) lowername from emp;
文件存储格式
Hive支持的存储数据的格式主要有:TEXTFILE 、SEQUENCEFILE、ORC、PARQUET。
列式存储和行式存储:
如图左边为逻辑表,右边第一个为行式存储,第二个为列式存储。
1.行存储的特点:查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。
2.列存储的特点:因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。
EXTFILE和SEQUENCEFILE的存储格式都是基于行存储的;
ORC和PARQUET是基于列式存储的。
- TextFile格式:默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用,但使用Gzip这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
-
Orc (Optimized Row Columnar)是Hive 0.11版里引入的新的存储格式。
如图所示可以看到每个Orc文件由1个或多个stripe组成,每个stripe一般为HDFS的块大小,每一个stripe包含多条记录,这些记录按照列进行独立存储,对应到Parquet中
Parquet格式:Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。
1)行组(Row Group):每一个行组包含一定的行数,在一个HDFS文件中至少存储一个行组,类似于orc的stripe的概念。
2)列块(Column Chunk):在一个行组中每一列保存在一个列块中,行组中的所有列连续的存储在这个行组文件中。一个列块中的值都是相同类型的,不同的列块可能使用不同的算法进行压缩。
3)页(Page):每一个列块划分为多个页,一个页是最小的编码的单位,在同一个列块的不同页可能使用不同的编码方式。
通常情况下,在存储Parquet数据的时候会按照Block大小设置行组的大小,由于一般情况下每一个Mapper任务处理数据的最小单位是一个Block,这样可以把每一个行组由一个Mapper任务处理,增大任务执行并行度。Parquet文件的格式如图6-12所示。
上图展示了一个Parquet文件的内容,一个文件中可以存储多个行组,文件的首位都是该文件的Magic Code,用于校验它是否是一个Parquet文件,Footer length记录了文件元数据的大小,通过该值和文件长度可以计算出元数据的偏移量,文件的元数据中包括每一个行组的元数据信息和该文件存储数据的Schema信息。除了文件中每一个行组的元数据,每一页的开始都会存储该页的元数据,在Parquet中,有三种类型的页:数据页、字典页和索引页。数据页用于存储当前行组中该列的值,字典页存储该列值的编码字典,每一个列块中最多包含一个字典页,索引页用来存储当前行组下该列的索引,目前Parquet中还不支持索引页。
企业级调优
1、 Fetch抓取:Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。例如:SELECT * FROM employees;在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台。
在hive-default.xml.template文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。
2、本地模式(单机模式):大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。
表的优化
1、小表、大表Join:将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率;再进一步,可以使用map join让小的维度表(1000条以下的记录条数)先进内存。在map端完成reduce。
实际测试发现:新版的hive已经对小表JOIN大表和大表JOIN小表进行了优化。小表放在左边和右边已经没有明显区别。
2、大表Join大表:
a、空KEY过滤:有时join超时是因为某些key对应的数据太多,而相同key对应的数据都会发送到相同的reducer上,从而导致内存不够。此时我们应该仔细分析这些异常的key,很多情况下,这些key对应的数据是异常数据,我们需要在SQL语句中进行过滤。例如key对应的字段为空,操作如下:
b、空key转换:有时虽然某个key为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join的结果中,此时我们可以表a中key为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的reducer上。例如:
3、MapJoin(小表join大表):开启MapJoin参数设置
(1)设置自动选择Mapjoin
set hive.auto.convert.join = true; 默认为true
(2)大表小表的阈值设置(默认25M一下认为是小表):
set hive.mapjoin.smalltable.filesize=25000000;
4、Count(Distinct) 去重统计
5、行列过滤:列处理在select的时候只拿需要的列,如果有尽量用分区过滤,少用select *
行处理:行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤,比如:
hive (default)> select o.id from bigtable b
join ori o on o.id = b.id
where o.id <= 10;
通过子查询后,再关联表
hive (default)> select b.id from bigtable b
join (select id from ori where id <= 10 ) o on b.id = o.id;
6、分区、分桶
7、合理设置Map及Reduce数:
a、是不是map数量越多越好呢?不是,当我们有许多小文件的时候map初始化的时间远远大于逻辑处理时间。
b、是不是map的block越接近128m越好呢?不是的,当我们的block的size是128m的时候但是里面的列很少数据很多而且map的处理逻辑又十分的复杂,那么我们此时用一个map去做坑定能力有限。
针对上面的问题,我们需要采取两种方式,即减少map数和增加map数
8、小文件进行合并
9、合理设置Reduce数,reduce个数并不是越多越好?不是的过多的启动和关闭reduce会造成资源的消耗,另外过多的reduce会导致跟多的文件如果文件比较小的化那么就会产生很多小文件从而影响下一次的map操作
10、并行执行:Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么job可能就越快完成。
通过设置参数hive.exec.parallel值为true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。
11、严格模式:开启严格模式会禁止下面的操作:
a、对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。(即分区表必须加where条件)
b、对于order by必须使用limit
c、限制笛卡尔积
12、 JVM重用
13、推测执行
14、压缩