Hive入门

Hive基本概念

Hive:是Facebook开源解决海量结构化日志的数据统计工具

Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能

Hive本质:将HQL转化成MapReduce程序

  • Hive的数据存储在HDFS上
  • Hive分析数据底层的实现是MapReduce
  • 执行程序运行在yarn上

Hive的优缺点

优点:

​ 1、接口操作采用类SQL语法,提供快速开发的能力

​ 2、避免了去写MapReduce

​ 3、Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合

​ 4、Hive的优势在于处理大数据,因此延迟比较高

​ 5、Hive支持用户自定义函数

缺点:

​ 1、Hive的HQL表达有限

​ 1)迭代算法无法表达

​ 2)数据挖掘方面不太擅长,由于MapReduce的数据处理流程限制,效率更高的算法却无法实现

​ 2、Hive的效率比较低

​ 1)Hive自动生成MapReduce作业,通常情况下不够智能

​ 2)Hive调优比较困难,力度较粗

Hive的数据类型

基本类型:

Hive数据类型Java数据类型长度例子
TINYINTbyte1byte有符号整数20
SMALINTshort2byte有符号整数20
INTint4byte有符号整数20
BIGINTlong8byte有符号整数20
BOOLEANboolean8byte有符号整数TRUE 、 FALSE
FLOATfloat单精度浮点数3.1415
DOUBLEdouble双精度浮点数3.1415
Stringstring字符类型
TIMESTAMP时间类型
BINARY字节数组

Hive 中的String就跟数据库的VARCHAR一样是动态的,可以存储2GB的字符数

数据类型描述语法
STRUCT和C语言中的struct类似struct< street:string,city:string>
MAP和Java中的Map集合类似map(string , int )
ARRAY和Java中的List集合类似array(string)
类型转换

Hive的原子数据可以进行隐性类型转换,类似于Java中的类型转换。

隐性类型转换

1、任何整数类型都可以隐性的转化成换位更广的类型

2、所有整数类型,FLOAT和STRING类型都可以隐性的转化为DOUBLE

3、TINYINT、SMALINT、INT都可以转化为FLOAT

4、BOOLEAN类型不可以转化为其他类型

可以使用CAST进行类型转换

select '1'+2,cast('1'as int) + 2;

DDL数据定义

查询数据库

显示数据库

hive> show databases;

过滤数据库

hive> show databases like 't_';
查看数据

显示数据库信息

hive> desc database t_test;

显示数据库相信信息:extended

hive> desc database extended t_test;

切换数据库

hive> use t_test1;
修改数据库

alter database为数据库的dbproperies设置键值对属性值

hive>  alter database t_test set dbproperties('createtime'='2020622');

查看结果

hive> desc database extended t_hive; 
删除数据库

删除空数据库

hive> drop database t_test;

删除时判断数据库是否存在

hive> drop database if exists t_test;

不为空,强行删除:cascade

hive> drop database t_test cascade;
管理表

内部表

默认创建的表都是内部表,这种表Hive会控制着数据的生命周期,当我们删除一个内部表的时候,Hive也会删除这个表中的数据。Hive会将这些表默认存储在配置项hive.metastore.warehouse.dir定义的目录的子目录下。

外部表

因为表示外部表,Hive并非完全拥有这份数据,删除表不会删除掉数据,描述表的元数据信息会被删掉。

查询表的类型

hive> desc formatted t_test;

修改表为外部表

hive> alter table t_test set tblproperties('EXTERNAL'='TRUE');

修改表为内部表

hive> alter table t_test set tblproperties('EXTERNAL'='FALSE');

重命名表

hive> ALTER TABLE t_test RENAME TO a_test;

添加列

hive> alter table t_test add columns(deptdesc string);

更新列

hive> alter table t_test change column deptdesc desc string;

替换列

hive> alter table t_test replace columns(deptno string, dname string, loc string);

删除表

hive> drop table t_test;

DML数据操作

数据导入

像表中装载数据

hive> load data [local] inpath '路径' [overwrite] into table t_test [partition (partcoll=vall,...)];

1、local data : 加载数据

2、local:从本地加载到hive表中,否则是从HDFS中加载数据到hive表

3、inpath:表示加载数据的路径

4、overwrite:表示覆盖表中已经有的数据,否则表示追加

5、into table:表示要加载哪张表中

6、partcoll:表示上传到指定分区

通过查询语句插入数据

基本插入模式:

hive> inserte into table t_test values (1,'myz'),(2,'yz');

基本插入模式(根据表查询结果):

hive> inserte overwrite table t_test 
	select id, name from people 

1、inserte into:以追加的方式插入到表或分区,原有数据不会被删除

2、inserte overwrite:会覆盖表中已经存在的数据

多表多分区插入模式:

hive> from t_test 
	inserte overwrite table t_test partition(month='2020623')
	select id, name where month='2020620'
	inserte overwrite table t_test partition(month='2020621')
	select id, name where month='2020620'

**根据查询结果创建表:as select **

create table if not exists t_test 
as 
select id,name from t_txt;

创建表时通过Location指定加载数据路径

hive> create external table if not exists t_test(
	id int , name string 
	)
	row format delimited fields terminated by '\t'
	location '/student';

Import数据导入指定Hive表中

先用export 导出后,再将数据导入

hive> import table t_test
	from '/user/hive/warehouse/export/t_txt';
数据导出

Insert导出到本地

正常人谁用啊???
Hadoop导入到本地

hive> dfs -get /user/hive/warehouse/t_test /usr/local/hive/t_test;

hive shell命令导出

hive -f/e 执行语句或者脚本 > file

bin/hive -e 'select * from default.t_test;' > /usr/local/hive/data/export/t_test;

Export 导出到HDFS上

export table default.t_test to '/user/hive/warehouse/export/t_test';

export 和 import 主要用于两个Hadoop平台集群之间Hive表迁移

清除表数据

Truncate 只能删除管理表,不能删除外部表中数据

hive> truncate table t_test;

查询

常用函数

1:行数count

hive(default)> select count(*) from emp;

2:最大值max

hive (default)> select max(sal) from emp;

3:最小值min

hive (default)> select min(sal) from emp;

4:总和sum

hive (default)> select sum(sal) from emp; 

5:平均avg

hive (default)> select avg(sal) from emp;
Limit

限制返回行数

hive (default)> select * from emp limit 10;
Where

过滤条件,就跟SQL中一样(where中不能使用字段别名)

Like&RLike

跟SQL中的一样,模糊匹配,%代表0到多个,_代表一个字符

RLike是Hive的一个扩展功能,可以匹配Java中的正则表达式

分组

Group By

按照一个队列或者多个队列进行分组,用起来跟SQL一样

Having

having用于group by 后面,可以使用分组函数,where后面不能使用分组函数

Join

内连接(join…on…)

两张表进行连接的时候,连接条件匹配的数据会保留下来

左外连接

左边表符合条件的where子句的所有记录会返回

右外连接

右边表符合条件的where子句的所有记录会返回

满外连接

将返回所有匹配上where语句的数据,如任一表的指定字段没有符合条件的值,使用null代替

多表联查

大部分情况下,Hive会对每对JOIN连接对象启动一个MapReduce任务,从左到右,第一张表和第二张表启动一个MapReduce进行连接操作,然后会再启动一个MapReduce对第二张表和第三张表进行连接操作…以此类推

当三个或以上的表进行连接,如果连接条件的字段相同,那么还是只会启动一个MapReduce

排序

全局排序:Order by 只有一个Reducer

ASC :升序 DESC:降序

内部排序:Sort By

Sort By为每一个reduce产生一个排序文件。每个reduce内部进行排序,对全局结果集来讲不是排序

1、设置Reduce的数量

hive (default)> set mapreduce.job.reduces=3;

2、根据部门编号查看员工信息

hive (default)> select * from emp sort by deptno;

3、将查询结果导入到文件当中

hive (default)> insert overwrite local directory 
'/usr/local/data/sortby'
select * from emp sort by deptno;
分区

Distribute By(需设置多个reduce才能看到效果)

在某些情况下,我们需要某些行到哪个reduce中,通常为了后续的聚集操作。

distributie by 类似于MapReduce中partition(自定义分区),进行分区结合sort by 使用()

按照部门编号分区,再按照员工编号排序

hive (default)> insert overwrite local directory 
'/usr/local/data/distribute' 
select * from emp distribute by deptno sort by empno ;

1、distribute by 的分区规则是根据分区字段的hash码和reduce的个数进行模除后,余数分到同一个组

2、要求distribute by 语句要卸载sort by前面

**Cluster By **

就是distribute by 和 sort by 的组合版,不过只能升序

分区表分桶表

分区表

对应HDFS中的一个文件夹,该文件夹下是该分区所有的数据文件,其实也就是分目录,将一个大的数据集拆分成多个数据集,查询时指定分区从而提高效率。

分区表基础操作

引入分区表

20200628.log
20200629.log
20200630.log

创建分区表

hive (default)> create table dept_partition(
deptno int, dname string, loc string)
partitioned by (day string)
row format delimited fields terminated by '\t';

加载数据

加载数据的时候必须执行分区

load data local inpath '路径' partition(day='20200628')

查询表中数据

hive (default)> select * from dept_partition where day='20200628';
hive (default)> select * from dept_partition where day='20200628'
 union
 select * from dept_partition where day='20200629'
 union
 select * from dept_partition where day='20200630';

增加分区

创建单个分区

hive (default)> alter table dept_partition add partition(day='20200630');

同时创建多个分区

hive (default)> alter table dept_partition add 
partition(day='20200628') partition(day='20200629');

删除分区

删除单个分区

hive (default)> alter table dept_partition drop partition (day='20200630');

删除多个分区

hive (default)> alter table dept_partition drop partition (day='20200628'), partition(day='20200629');

查看分区表有多少个分区

hive (default)> show partitions dept_partition;

查看分区表结构

hive (default)> desc formatted dept_partition;
二级分区

将数据再进一步拆分

创建二级分区表

hive (default)> create table dept_partition2(
 deptno int, dname string, loc string)
 partitioned by (day string, hour string)
 row format delimited fields terminated by '\t';

加载数据

hive (default)> load data local inpath 
'/usr/local/hive/datas/20200628.log' into table
dept_partition2 partition(day='20200628', hour='12');

查询数据

hive (default)> select * from dept_partition2 where day='20200628' and hour='12';

把数据直接上传到分区目录上,让分区表和数据产生关联的三种方式

上传数据后修复

--修复命令--
hive> msck repair table dept_partition2;

上传数据后添加分区

--添加分区--
hive (default)> alter table dept_partition2 add partition(day='2020628',hour='14');

创建文件夹后load数据到分区

动态分区调整

关系型数据库中,对分区表进行插入数据的时候,数据库自动会根据分区字段的值,将数据插入到对应的分区,即动态分区。

1、开启动态分区

hive.exec.dynamic.partition=true

2、设置非严格模式(默认strict至少要指定一个分区为静态分区,nonstrict允许所有分区字段都可以使用静态分区)

hive.exec.dynamic.partition.mode=nonstrict

3、所有执行MapReduce节点上,最大可以创建多少个动态分区,默认1000

hive.exec.max.dynamic.partitions=1000

4、在每个MapReduce的节点上,最大可以创建多少个动态分区,设置多少根据业务来,默认100

hive.exec.max.dynamic.partitions.pernode=100

5、整个MR Job中,最大可以创建多少个HDFS文件,默认100000

hive.exec.max.created.files=100000

6、当有空分区生成时,是否抛出异常,默认false

hive.error.on.empty.partition=false
分桶表

分区提供一个隔离数据和优化查询的便利方式。但是并不是所有的数据集都可以形成合理的分区,对于一张表或者分区,Hive 可以进一步组织成桶,就是更为细粒度的数据范围划分。

分桶是将数据集拆分成更容易管理的若干部分的另一种技术。

分区针对的是数据存储路径,分桶针对的是数据文件。

1、创建分桶表

create table stu_buck(id int, name string)
clustered by(id) 
into 4 buckets
row format delimited fields terminated by '\t';

2、查看结构

hive (default)> desc formatted stu_buck;

3、导入数据到桶中

hive (default)> load data inpath '/test.txt' into table stu_buck;

hive(default)>insert into table stu_buck select * from text;

分桶规则

Hive对采用分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶中。

1、reduce的个数设置为-1,让job自行决定需要使用多少个reduce或者将reduce的个数设置为大于或等于桶数量

2、从hdfs中load数据到分桶表中,避免本地文件找不到问题

3、不要使用本地模式

抽样查询

对于非常大的数据量,有时候用户不是需要所有数据,而是一个具有代表性的数据,Hive有抽样查询可以解决。

语法: TABLESAMPLE(BUCKET x OUT OF y)

x的值必须小于等于y的值

hive (default)> select * from text tablesample(bucket 1 out of 4 on id);

函数

查看系统自带的函数

hive> show functions;

显示自带的函数的用法

hive> desc function upper;

详细显示自带的函数的用法

hive> desc function extended upper;
常用内置函数

nvl:nvl(value,default_value)

如果value为null,则nvl函数返回default_value的值,否则返回value的值,如果两个参数都为null,则返回null

行转列

CONCAT(string A/col,string B/col…)返回输入字符串后连接的结果,支持任意个输入字符串

CONCAT_WS(separator, str1, str2,…):第一个参数剩余参数间的间隔符。分隔符可以是与剩余参数一样的字符串,如果分隔符为null,返回值也将为null,这个函数会跳过分隔符参数后的任何null和空字符串,分隔符将被加到被连接的字符串之间。

COLLECT_SET(col):只接受基本数据类型,它的主要作用是将某字段的值进行去重 汇总,产生 Array 类型字段

列转行

EXPLODE(col):将 hive 一列中复杂的 Array 或者 Map 结构拆分成多行

LATERAL VIEW:LATERAL VIEW udtf(expression) tableAlias AS columnAlias

用于和 split, explode 等 UDTF 一起使用,它能够将一列数据拆成多行数据,在此 基础上可以对拆分后的数据进行聚合。

开窗函数

over():指定分析函数工作的数据窗口大小,这个窗口大小可能会随着行的变化而变化。

CURRENT ROW:当前行

n PRECEDING:往前 n 行数据

n FOLLOWING:往后 n 行数据

UNBOUNDED:起点,

​ UNBOUNDED PRECEDING 表示从前面的起点,

​ UNBOUNDED FOLLOWING 表示到后面的终点

LAG(col,n,default_val):往前第 n 行数据

LEAD(col,n, default_val):往后第 n 行数据

NTILE(n):把有序窗口的行分发到指定数据的组中,各个组有编号,编号从 1 开始,对 于每一行,NTILE 返回此行所属的组的编号。注意:n 必须为 int 类型。

name,orderdate,cost

jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94
create table business(
name string,
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/usr/local/data/business.txt" into table business;
-- 查看顾客上次购买时间
-- lag往前第N行数据
select 
	name,
	orderdate,
	cost,
	lag(orderdate,1,'1900-01-01') over(partition by name order by orderdate ) as time1,
	lag(orderdate,2) over (partition by name order by orderdate) as time2 
from 
	business;
	
-- 查询前20%时间的订单信息
select * from (
 select 
	name,
	orderdate,
-- 	ntile将数据分成五分,按照orderdata进行排序
	cost, ntile(5) over(order by orderdate) sorted
 from 
	business
) t
where 
-- 获取第一份数据也就是前20%数据
	sorted = 1;

-- 查询顾客的购买明细及月购买总额
select 
	name,
	orderdate,
	cost,
	sum(cost) over(partition by month(orderdate)) 
from business;


-- 查询四月购买的顾客及人数
select 
	name,
	count(*) over () 
from 
	business
where
	substring(orderdate,1,7) = '2017-04'
group by 
	name;
Rank

rank() :排序相同时会重复,总数不会变

dense_rank():排序相同时会重复,总数会减少

row_number():会根据顺序计算

自定义函数

自定义函数分为三种:UDF(一进一出) UDAF(多进一出) UDTF(一进多出)

自定义UDF函数

1、改pom

  <dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.2</version>
        </dependency>
    </dependencies>

2、创建类继承,继承GenericUDF

package com.myz.hive;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

import java.util.prefs.PreferencesFactory;

public class UDF extends GenericUDF {

    public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
     if (objectInspectors.length != 1){
         throw new UDFArgumentException("参数长度不为1");
     }

        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

    public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
        String s = deferredObjects[0].get().toString();
        if (s == null){
            return 0;
        }
        return s.length();
    }

    public String getDisplayString(String[] strings) {
        return null;
    }
}

3、打包

4、将jar包添加到hive的classpath

hive (default)> add jar /opt/module/data/myudf.jar;

5、创建函数与开发好的Java class关联

hive (default)> create temporary function my_len as "com.myz.hive.UDF";

6、使用

hive (default)> select ename,my_len(ename) ename_len from emp;

自定义UDTF函数

1、继承GenericUDTF

package com.myz.hive;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;

import java.util.ArrayList;
import java.util.List;

public class UDTF extends GenericUDTF {

    private List<String> outList = new ArrayList<>();

    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        List<String> fieldNames = new ArrayList<>();
        List<ObjectInspector> fieldOIs = new ArrayList<>();
        fieldNames.add("lineToWord");
        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,fieldOIs);
    }

    @Override
    public void process(Object[] objects) throws HiveException {
        //获取原始数据
        String s = objects[0].toString();
        //获取第二个传参数   ","
        String spilt = objects[1].toString();
        //原始数据按照分隔符进行切分
        String[] split = s.split(spilt);
        //遍历切分后的结果
        for (String s1 : split) {
            //清空
            outList.clear();
            //将每一个新词添加到集合中
            outList.add(s1);
            //写出
            forward(outList);
        }
    }

    @Override
    public void close() throws HiveException {

    }
}

2、之后步骤同上

压缩和存储

总之,hive表中的数据存储一般选择用orc或parquet

​ 压缩方式一般选择snappy,lzo

调优

执行计划

explain 详细执行计划:explain extended

Fetch抓取

fetch抓取:hive对于某些情况的查询可以不必使用MapReduce计算。

在 hive-default.xml.template 文件中hive.fetch.task.conversion默认为more,老版本默认为minimal,把该属性修改为more以后,在全局查找、字段查找、limit查找等都不走MapReduce

<property>
 <name>hive.fetch.task.conversion</name>
 <value>more</value>
 <description>
  Expects one of [none, minimal, more].
  Some select queries can be converted to single FETCH task minimizing latency.
  Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incurs RS), 
  lateral views and joins.
  0. none : disable hive.fetch.task.conversion
  1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
  2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and 
virtual columns)
 </description>
</property>

本地模式

hive可以通过本地模式在单台服务器上来处理一些比较小的数据集,处理时间明显缩短

通过设置hive.exec.mode.local.auto的值为true

set hive.exec.mode.local.auto=true; //开启本地 mr
//设置 local mr 的最大输入数据量,当输入数据量小于这个值时采用 local mr 的方式,默认为 134217728,
即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//设置 local mr 的最大输入文件个数,当输入文件个数小于这个值时采用 local mr 的方式,默认为 4
set hive.exec.mode.local.auto.input.files.max=10;
表优化

小表大表join

将key相对于比较分散的,数据量比较小的表放在左边,可以使用map join让小的维度的表先进内存。

新版hive放左放右都一样

开启mapjoin参数设置

--自动选择mapjoin
set hive.auto.convert.join = true; 默认为 true
--大表小表的阈值设置,默认25M下就是小表
set hive.mapjoin.smalltable.filesize = 25000000;

大表join大表

1、空key过滤

有时候join超时是因为某些key对应的数据太多,相同的key对应的数据都会发送到相同的reduce上,从而导致内存不够。

很多情况下,这些key对应的数据是异常数据,我们需要在SQL中进行过滤,例如:空key

2、空key转换

有时候某个key对应的空数据有很多,但是相应的数据不是异常数据,必须要包含在join中,那就可以给空key赋一个随机值,使数据均匀的分不到不同的reduce上

Group By

默认情况下,Map阶段同一个key数据分发给一个reduce,当一个key数据过大时就会倾斜了。

并不是所有聚合都需要在reduce阶段完成,map阶段也可以完成部分聚合操作,最后在reduce端得到结果

1、开启map端聚合参数设置

​ 1)是否在map端聚合,默认为true

set hive.map.aggr = true

​ 2)在map端进行聚合操作的条目数目

set hive.groupby.mapaggr.checkinterval = 100000

​ 3)有数据倾斜的时候进行负载均衡,默认为false

set hive.groupby.skewindata = true

当选定项为true的时候,生成执行计划,会有两个MRjob,第一个MRjob中,Map的输出结果会随机分布到reduce中,每个reduce中做部分聚合操作,然后输出,这样最终相同的group by有可能被分到不同的reduce中,从而达到负载均衡的目的

第二个MRjob在根据预处理的数据结果按照Group by key 分布到reduce中(可以保证相同的Group By Key被分布到同一个reduce中),最后完成最终的聚合操作。

Count(Distinct)去重统计

数据量大的情况下,由于Count Distinct操作需要用到一个Reduce Task来完成,这一个reduce需要处理的数据量太大,就会导致整个job很难完成,一般count distinct使用先group by 在count的方式替换,但是要注意group by数据倾斜问题

会多用一个job完成工作,但是在数据量大的情况下是值得的。

笛卡尔积

join的时候不添加on条件,或者添加无效的on条件,hive只会用一个reduce来完成笛卡尔积

行列过滤

列处理:在select中只拿需要的列,如果有分区,尽量使用分区过滤,少用select *

行处理:在分区裁剪中,当使用外关联的时候,如果将副表的过滤条件写在where后面,那么就会先全表关联,之后过滤

设置map数和reduce数

1)通常情况下,作业会通过 input 的目录产生一个或者多个 map 任务。 主要的决定因素有:input 的文件总个数,input 的文件大小,集群设置的文件块大小。

2)是不是 map 数越多越好? 答案是否定的。如果一个任务有很多小文件(远远小于块大小 128m),则每个小文件 也会被当做一个块,用一个 map 任务来完成,而一个 map 任务启动和初始化的时间远远大 于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的 map 数是受限的。

3)是不是保证每个 map 处理接近 128m 的文件块,就高枕无忧了? 答案也是不一定。比如有一个 127m 的文件,正常会用一个 map 去完成,但这个文件只 有一个或者两个小字段,却有几千万的记录,如果 map 处理的逻辑比较复杂,用一个 map 任务去做,肯定也比较耗时。

针对上面的问题 2 和 3,我们需要采取两种方式来解决:即减少 map 数和增加 map 数;

复杂文件增加 Map 数

当 input 的文件都很大,任务逻辑复杂,map 执行非常慢的时候,可以考虑增加 Map 数, 来使得每个 map 处理的数据量减少,从而提高任务的执行效率。

computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M 公式.

调整 maxSize 最大值。让 maxSize 最大值低于 blocksize 就可以增加 map 的个数。

 --设置最大切片值
 set mapreduce.input.fileinputformat.split.maxsize=100;

小文件进行合并

1、在 map 执行前合并小文件,减少 map 数:CombineHiveInputFormat 具有对小文件进行合 并的功能(系统默认的格式)。HiveInputFormat 没有对小文件合并功能。

set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

2、在 Map-Reduce 的任务结束时合并小文件的设置:

​ 1)在map-only 任务结束时合并小文件,默认为true

SET hive.merge.mapfiles = true;

​ 2)在 map-reduce 任务结束时合并小文件,默认 false

SET hive.merge.mapredfiles = true;

​ 3)合并文件的大小,默认 256M

SET hive.merge.size.per.task = 268435456;

​ 4)当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge

SET hive.merge.smallfiles.avgsize = 16777216;

合理设置reduce数量

1、

​ 1)每个reduce处理的数据量默认是256M

hive.exec.reducers.bytes.per.reducer=256000000

​ 2)每个任务最大的reduce数,默认为1009

hive.exec.reducers.max=1009

​ 3)计算reduce数公式

N=min(参数 2,总输入数据量/参数 1)

2、mapred - default.xml

设置每个job的reduce数量

set mapreduce.job.reduces = 15;

3、reduce的数量不是越多越好

​ 1)过多的启动和初始化 reduce 也会消耗时间和资源;

​ 2)另外,有多少个 reduce,就会有多少个输出文件,如果生成了很多个小文件,那 么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;

在设置 reduce 个数的时候也需要考虑这两个原则:

​ 处理大数据量利用合适的 reduce 数;

​ 使单个 reduce 任务处理数据量大小要合适;

并行执行

Hive 会将一个查询转化成一个或者多个阶段,这样的阶段可以是 MapReduce 阶段、抽 样阶段、合并阶段、limit 阶段,或者 Hive 执行过程中可能需要的其他阶段。

默认情况下, Hive 一次只会执行一个阶段。不过,某个特定的 job 可能包含众多的阶段,而这些阶段可能 并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个 job 的执行 时间缩短。不过,如果有更多的阶段可以并行执行,那么 job 可能就越快完成。

通过设置参数 hive.exec.parallel 值为 true,就可以开启并发执行。不过,在共享集群中, 需要注意下,如果 job 中并行阶段增多,那么集群利用率就会增加,前提是系统资源得到位,没资源,并行也起不来

//打开任务并行执行
set hive.exec.parallel=true; 
//同一个 sql 允许最大并行度,默认为8。
set hive.exec.parallel.thread.number=16; 
严格模式

通过设置防止一些,危险的操作

1、分区表不使用分区过滤 将 hive.strict.checks.no.partition.filter 设置为 true 时,对于分区表,除非 where 语句中含 有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有 进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。

2、使用 order by 没有 limit 过滤 ,将 hive.strict.checks.orderby.no.limit 设置为 true 时,对于使用了 order by 语句的查询,要 求必须使用 limit 语句。因为 order by 为了执行排序过程会将所有的结果数据分发到同一个 Reducer 中进行处理,强制要求用户增加这个 LIMIT 语句可以防止 Reducer 额外执行很长一 段时间。

3、笛卡尔积 将 hive.strict.checks.cartesian.product 设置为 true 时,会限制笛卡尔积的查询。对关系型数 据库非常了解的用户可能期望在 执行 JOIN 查询的时候不使用 ON 语句而是使用 where 语 句,这样关系数据库的执行优化器就可以高效地将 WHERE 语句转化成那个 ON 语句。不幸 的是,Hive 并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情 况。

JVM重用、压缩…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值