一.简介
1.定义
是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类SQL查询功能,本质是将HQL转化成MapReduce程序
- Hive处理的数据存储在HDFS
- Hive分析数据底层的实现是MapReduce
- 执行程序运行在Yarn上
2.优缺点
优点
- 操作接口采用类SQL语法,提供快速开发的能力(简单,容易上手)
- 避免了去写MapReduce,减少开发人员的学习成本
- Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合
- Hive优势在于处理大数据,对于处理小数据没有优势,因为Hive的执行延迟比较高
- Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数
缺点
- Hive的HQL表达能力有限:迭代式算法无法表达;数据挖掘方面不擅长,由于MapReduce数据处理流程的限制,效率更高的算法却无法实现
- Hive的效率比较低:Hive自动生成的MapReduce作业,通常情况下不够智能化;Hive调优比较困难,粒度较粗
3.架构原理
4.和数据库比较
- 查询语言:由于SQL被广泛应用在数据仓库中,因此,专门针对Hive的特性设计了类SQL的查询语言HQL
- 数据存储位置:所有Hive的数据都是存储在HDFS中的,而数据库则可以将数据保存在块设备或者本地文件系统中
- 数据更新:由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少,因此,Hive中不建议对数据的改写,所有的数据都是在加载的时候确定好的;而数据库中的数据通常是需要经常修改的
- 执行:Hive中大多数查询的执行是通过Hadoop提供的MapReduce来实现的;而数据库通常有自己的执行引擎
- 执行延迟:Hive执行有延迟,数据库的执行延迟较低;当然,这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive的并行计算就能体现出优势
- 可扩展性:Hive是建立在Hadoop上的,因此Hive的可扩展性和Hadoop的可扩展性是一致的
- 数据规模:Hive建立在集群上并可以利用MapReduce进行并行计算,因此可以支持很大规模的数据,数据库可以支持的数据规模较小
二.数据类型
1.基本数据类型
2.集合数据类型
3.类型转换
- 任何整数类型都可以隐式地转换为一个范围更广的类型
- 所有整数类型,float和string类型都可以隐式地转换成double
- tinyint,smallint,int都可以转换为float
- boolean类型不可以转换为任何其它的类型
- 可以使用cast操作显式进行数据类型转换
三.DDL数据定义
1.创建数据库
-- 创建一个数据库
create database db_hive;
-- 避免要创建的数据库已经存在错误,增加if not exists判断
create database if not exists db_hive;
-- 创建一个数据库,指定数据库在HDFS上存放的位置
create database db_hive location '/db_hive.db';
2.查询数据库
-- 显示数据库
show databases;
-- 过滤显示查询的数据库
show databases like 'db_hive*';
-- 显示数据库信息
desc database db_hive;
-- 显示数据库详细信息
desc database extended db_hive;
-- 切换到当前数据库
use db_hive;
3.修改数据库
用户可以使用alter database命令为某个数据库的dbproperties设置键值对属性值,来描述这个数据库的属性信息;数据库的其他元数据信息都是不可更改的,包括数据库名和数据库所在的目录位置
alter database db_hive set dbproperties('createtime'='20221230');
-- 在hive中查看修改结果
desc database extended db_hive;
4.删除数据库
-- 删除空数据库
drop database db_hive;
-- 如果删除的数据库不存在,最好采用if exists判断数据库是否存在
drop database if exists db_hive;
-- 如果数据库不为空,可以采用cascade命令,强制删除
drop database db_hive cascade;
5.创建表
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_commnet],...)]
[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]
[TALPROPERTIES (property_name=property_value,...)]
[AS select_statement]
- CREATE TABLE:创建一个指定名字的表;如果相同名字的表已经存在,则抛出异常;用户可以用IF NOT EXISTS选项来忽略这个异常
- EXTERNAL:可以让用户创建一个外部表,在建表的同时可以指定一个指向实际数据的路径,在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据
- COMMENT:为表和列添加注释
- PARTITIONED BY:创建分区表
- CLUSTERED BY:创建分桶表
- SORTED BY:不常用,对桶中的一个或多个列另外排序
- ROW FORMAT:用户在建表的时候可以自定义SerDe或者使用自带的SerDe;在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的SerDe,Hive通过SerDe确定表的具体的列的数据
- STORED AS:指定存储文件类型
- LOCATION:指定表在HDFS上的存储位置
- AS:后跟查询语句,根据查询结果创建表
- LIKE:允许用户复制现有的表结构,但是不复制数据
6.管理表
默认创建的表都是管理表,也被称为内部表
因为这种表,Hive会或多或少地控制着数据的生命周期
Hive默认情况下会将这些表的数据存储在由配置项hive.metastore.warehouse.dir所定义的目录的子目录下;当我们删除一个管理表时,Hive也会删除这个表中的数据
管理表不适合和其他工具共享数据
-- 普通创建表
create table if not exists student(
id int,name string
)
row format delimited fields terminated by '\t'
stored as textfile
location '/user/hive/warehouse/student';
-- 根据查询结果创建表(查询的结果会添加到新创建的表中)
create table if not exists student2 as select id,name from student;
-- 根据已经存在的表结构创建表
create table if not exists student3 like student;
-- 查询表的类型
desc formatted student;
7.外部表
因为表是外部表,所以Hive并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉
管理表和外部表的适用场景:每天将收集到的网站日志定期流入HDFS文本文件。在外部表(原始日志表)的基础上做大量的统计分析,用到的中间表,结果表使用内部表存储,数据通过SELECT+INSERT进入内部表
-- 分别创建部门和员工外部表,并向表中导入数据
-- 上传数据到HDFS
dfs -mkdir /student;
dfs -put /opt/module/datas/student.txt /student;
-- 创建外部表
create external table stu_external(
id int,name string)
row format delimited fields terminated by '\t'
location '/student';
-- 查看创建的表
select * from stu_external;
-- 查看表格式化数据
desc formatted dept;
-- 删除外部表
drop table stu_external;
8.管理表和外部表的互相转换
-- 查询表的类型
desc formatted student;
-- 修改内部表student为外部表
alter table student set tblproperties('EXTERNAL'='TRUE');
-- 查询表的类型
desc formatted student;
-- 修改外部表student为内部表
slter table student set tblproperties('EXTERNAL'='FALSE');
-- 查询表的类型
desc formatted student;
9.分区表
实际上就是对应一个HDFS文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件
Hive中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集
在查询时通过where子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多
-- 创建分区表语法:分区字段不能是表中已经存在的数据,可以将分区字段看作表的伪列
create table dept_partition(
deptno int,dname string,loc string
)
partitioned by (month string)
row format delimited fields terminated by '\t';
-- 加载数据到分区表中
load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='202212');
-- 单分区查询
select * from dept_partition where month='202212';
-- 多分区联合查询
select * from dept_partition where month='202212'
union
select * from dept_partition where month='202301'
union
select * from dept_partition where month='202302';
-- 创建单个分区
alter table dept_partition add partition(month='202212');
-- 同时创建多个分区
alter table dept_partition add partition(month='202211'),partition(month='202210');
-- 删除单个分区
alter table dept_partition drop partition(month='202209');
-- 同时删除多个分区
alter table sept_partition drop partition(month='202208'),partition(month='202207');
-- 查看分区表有多少分区
show partition dept_partition;
-- 查看分区表结构
desc formatted dept_partition;
-- 注意事项
-- 创建二级分区表
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='202212',day='13');
-- 查询分区数据
select * from dept_partition2 where month='202212' and day ='13';
-- 把数据直接上传到分区目录上,让分区表和数据产生关联的三种方式
-- 1.上传数据后修复
dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=202212/day=12; -- 上传数据
select * from dept_partition2 where month='202212' and day='12'; -- 查询数据
msck repair table dept_partition2; -- 执行修复命令
-- 2.上传数据后添加分区
dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=202212/day=11; -- 上传数据
alter table dept_partition2 add partition(month='202212',day='11'); -- 执行添加分区
select * from dept_partition2 where month='202212' and day='11';
-- 3.创建文件夹后load数据到分区
dfs -mkdir -p /user/hive/warehouse/dept_partition2/month=202212/day=10; -- 上传数据
load data local inpath '/opt/module/datas/dept.txt' into table dept_partition2 partition(month='202212',day='10'); -- 上传数据
select * from dept_partition2 where month='202212' and day='10'; --查询数据
10.修改表
-- 重命名表
alter table table_name rename to new_table name
-- 更新列
alter table table_name change [column] col_old_name col_new_name column_type [COMMENT col_comment][FIRST|AFTER column_name]
-- 添加和替换列
alter table table_name add|replace columns (col_name data_type [COMMENT col_comment],...)
-- 删除表
drop table dept_partition;
四.DML数据操作
1.数据导入
①向表中装载数据(load)
load data [local] inpath '/opt/module/datas/student.txt' [overwrite] into table student [partition(partcol11=val1,...)];
- load data:表示加载数据
- local:表示从本地加载数据到hive表,否则从HDFS加载数据到hive表
- inpath:表示加载数据的路径
- overwrite:表示覆盖表中已有的数据,否则表示追加
- into table:表示加载到哪张表
- student:表示具体的表
- partition:表示上传到指定分区
-- 创建一张表
create table student(id string,name string) row format delimited fields terminated by '\t';
-- 加载本地文件到hive
load data local inpath '/opt/module/datas/student.txt' into table default.student;
-- 加载HDFS文件到hive中
-- 上传文件到HDFS
dfs -put /opt/module/datas/student.txt /user/aaaaa/hive;
-- 加载HDFS上数据
load data inpath '/user/aaaaa/hive/student.txt' into table default.student;
-- 加载数据覆盖表中已有的数据
-- 上传文件到HDFS
dfs -put /opt/module/datas/student.txt /user/aaaaa/hive
-- 加载数据覆盖表中已有的数据
load data inpath '/user/aaaaa/hive/student.txt' overwrite into table default.student;
②通过查询语句向表中插入数据(insert)
-- 创建一张分区表
create table student(id int,name string) partitioned by (month string) row format delimited fields terminated by '\t';
-- 基本插入数据
insert into table student partition(month='202210') values(1,'wangwu'),(2,'zhaoliu');
-- 基本模式插入(根据单张表查询结果)
-- insert into:以追加数据的方式插入到表或分区,原有数据不会删除
-- insert overwrite:会覆盖表或分区中已存在的数据
-- 注意:insert不支持插入部分字段
insert overwrite table student partition(month='202210')
select id,name from student where month='202211';
-- 多表(多分区)插入模式(根据多张表查询结果)
from student
insert overwrite table student partition(month='202212')
select id,name where month='202210'
insert overwrite table student partition(month='202211')
select id,name where month='202210';
③查询语句中创建表并加载数据(as select)
-- 根据查询结果创建表(查询的结果会添加到新创建的表中)
create table if not exists student3 as select id,name from student;
④创建表时通过location指定加载数据路径
-- 上传数据到hdfs上
dfs -mkdir /student;
dfs -put /opt/module/datas/student.txt /student;
-- 创建表,并指定在hdfs上的位置
create external table if not exists student5(
id int,name string
)
row format delimited fields terminated by '\t'
location '/student';
-- 查询数据
select * from student5;
⑤import数据到指定Hive表中
-- 注意:先用export导出后,再将数据导入
import table student2 partition(month='202212') from '/user/hive/warehouse/export/student';
2.数据导出
①insert导出
-- 将查询结果导出到本地
insert overwrite local directory '/opt/module/datas/export/student' select * from student;
-- 将查询结果格式化导出到本地
insert overwrite local directory '/opt/module/datas/export/student1' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;
-- 将查询结果导出到hdfs(没有local)
insert overwrite directory '/user/aaaaa/student2' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' select * from student;
②hadoop命令导出到本地
dfs -get /user/hive/warehouse/student/month=202212/opt/module/datas/export/student3.txt;
③hive shell命令导出
hive -f/-e 执行语句或者脚本 > file
④export导出到hdfs上
-- export和import主要用于两个hadoop平台集群之间hive表迁移
export table default.student to '/user/hive/warehouse/export/student';
五.查询
1.基本查询
①全表和特定列查询
-- 全表查询
select * from emp;
-- 选择特定列查询
select empno,ename from emp;
- SQL语言大小写不敏感
- SQL可以写在一行或多行
- 关键字不能被缩写也不能分行
- 各子句一般要分行写
- 使用缩进提高语句的可读性
②列别名
select ename AS name,deptno dn from emp;
- 重命名一个列
- 便于计算
- 紧跟列名,也可以在列名和别名之间加入关键字 AS
③算术运算符
- A+B:A和B相加
- A-B:A减去B
- A*B:A和B相乘
- A/B:A除以B
- A%B:A对B取余
- A&B:A和B按位取与
- A|B:A和B按位取或
- A^B:A和B按位取异或
- ~A:A按位取反
④常用函数
- count
- max
- min
- sum
- avg
⑤limit语句
- 典型的查询会返回多行数据
- limit子句用于限制返回的行数
2.where语句
- 使用where子句,将不满足条件的行过滤掉
- where子句紧随from子句
- where子句中不能使用字段别名
①比较运算符
between / in / is null
②like和rlike
- 使用like运算选择类似的值
- 选择条件可以包含字符或数字:%代表零个或多个字符,_代表一个字符
- rlike子句是hive中这个功能的一个扩展,其可以通过java的正则表达式这个更强大的语言来指定匹配条件
③逻辑运算符
- and:逻辑并
- or:逻辑或
- not:逻辑否
3.分组
①group by
- 通常会和聚合函数一起使用
- 按照一个或者多个列对结果进行分组,然后对每个组执行聚合操作
②having
- where后面不能写分组函数,having后面可以使用分组函数
- having只用于group by分组统计语句
4.join
- hive支持通常的SQL join语句,但是只支持等值连接,不支持非等值连接
- 内连接:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来
- 左外连接:join操作符左边表中符合where子句的所有记录将会被返回
- 右外连接:join操作符右边表中符合where子句的所有记录将会被返回
- 满外连接:将会返回所有表中符合where语句条件的所有记录。如果任一表的指定字段没有符合条件的值的话,那么就是用null值替代
- 多表连接:连接n个表,至少需要n-1个连接条件
- 笛卡尔积:省略连接条件,连接条件无效,所有表中的所有行互相连接
- hive join目前不支持在on子句中使用谓词or
5.排序
- order by:全局排序,只有一个reducer
- asc:升序(默认)
- desc:降序
- sort by:对于大规模的数据集order by的效率非常低,在很多情况下,并不需要全局排序,此时可以使用sort by;sort by为每个reducer产生一个排序文件,每个reducer内部进行排序,对全局结果集来说不是排序
- distribute by:在有些情况下,我们需要控制某个特定行应该到哪个reducer,通常是为了后续的聚集操作,distribute by类似MR中partition(自定义分区),进行分区,结合sort by使用;对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果
- cluster by:当sort by和distribute by字段相同时,可以使用cluster by方式;但排序只能是升序排序,不能指定排序规则为asc或desc
6.分桶及抽样查询
- 分区提供一个隔离数据和优化查询的便利方式
- 并非所有的数据集都可以形成合理的分区
- 对于一张表或分区,hive可以进一步组织成桶,也就是更为细粒度的数据范围划分
- 分桶是将数据集分解成更容易管理的若干部分的技术
- 分区针对的是数据的存储路径;分桶针对的是数据文件
7.其它常用的查询函数
空字段赋值
- nvl:给值为null的数据赋值,它的格式是nvl(value,default_value),功能是如果value为null,则nvl函数返回default_value的值,否则返回value的值,如果两个参数都是null,则返回null
行转列
- concat(string A/col,string B/col...):返回输入字符串连接后的结果,支持任意个输入字符串
- concat_ws(separator,str1,str2,...):是一个特殊形式的concat();第一个参数剩余参数间的分隔符,分隔符可以是与剩余参数一样的字符串,如果分隔符是null,返回值也是null,这个函数会跳过分隔符参数后的任何null和空字符串,分隔符将被加到被连接的字符串之间
- collect_set(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段
列转行
- explode(col):将hive一列中复杂的array或者map结构拆分成多行
- lateral view:用于和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类型
rank
- rank():排序相同时会重复,总数不会变
- dense_rank():排序相同时会重复,总数会减少
- row_number():会根据顺序计算
六.函数
1.系统内置函数
-- 查看系统自带的函数
show functions;
-- 显示自带的函数的用法
desc function upper;
-- 详细显示自带的函数的用法
desc function extended upper;
2.自定义函数
- hive自带了一些函数,比如max/min等,但是数量有限,自己可以通过自定义UDF来方便地扩展
- 当hive提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数
- 根据用户自定义函数类别分类:UDF(user defined function,一进一出),UDAF(user defined aggregation function,聚集函数,多进一出,类似于count/max/min),UFTF(user defined table generating functions,一进多出,如lateral view explore())
- UDF必须要有返回类型,可以返回null,但是返回类型不能为void
编程步骤
- 继承org.apache.hadoop.hive.ql.exec.UDF
- 需要实现evaluate函数,evaluate函数支持重载
- 在hive命令行窗口创建函数:添加jar,创建function
- 在hive命令行窗口删除函数
七.调优
1.fetch抓取
- hive中对某些情况的查询可以不必使用MapReduce计算
- 在这种情况下,hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台
- 在hive-default.xml.template文件中hive.fetch.task.conversion默认是more,在全局查找,字段查找,limit查找等都不走MapReduce
2.本地模式
- 大多数的hadoop job是需要hadoop提供的完整的可扩展性来处理大数据集的
- 不过,有时hive的输入数据量是非常小的,在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多得多
- 对于大多数情况,hive可以通过本地模式在单台机器上处理所有的任务;对于小数据集,执行时间可以明显被缩短
- 用户可以通过设置hive.exec.mode.local.auto的值为true,来让hive在适当的时侯自动启动这个优化,默认是false
3.表的优化
大表,小表join
- 新版的hive已经对小表join大表和大表join小表进行了优化,小表放在左边和右边已经没有明显区别
大表join大表
- 空key过滤:有时join超时是因为某些key对应的数据太多,而相同的key对应的数据都会发送到相同的reducer上,从而导致内存不够。此时我们应该仔细分析这些异常的key,很多情况下,这些key对应的数据是异常数据,我们需要在SQL语句中进行过滤
- 空key转换:有时虽然某个key为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join的结果中,此时我们可以表a中key为空的字段赋一个随机的值,使得数据随机均匀地分到不同的reducer上
mapjoin(小表join大表)
- 如果不指定mapjoin或者不符合mapjoin的条件,那么hive解析器会将join操作转换成common join,即在reduce阶段完成join;容易发生数据倾斜;可以用mapjoin把小表全部加载到内存在map端进行join,避免reducer处理
group by
- 默认情况下,map阶段同一key数据分发给一个reduce,当一个key数据过大时就倾斜了
- 并不是所有的聚合操作都需要在reduce端完成,很多聚合操作都可以先在map端进行部分聚合,最后在reduce端得出最终结果
count(distinct)去重统计
- 数据量小的时候无所谓,数据量大的情况下,由于count distinct的全聚合操作,即使设定了reduce task个数,set mapred.reduce.tasks=100,hive也只会启动一个reducer,这就造成一个reduce处理的数据量太大,导致整个job很难完成,一般count distinct使用先group by再count的方式替换
笛卡尔积
- 尽量避免笛卡尔积,join的时候不加on条件,或者无效的on条件,hive只能使用1个reducer来完成笛卡尔积
行列过滤
- 列处理:在select中,只拿需要的列,如果有,尽量使用分区过滤,少用select *
- 行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在where后面,那么就会先全表关联,之后再过滤
动态分区调整
- 关系型数据库中,对分区表insert数据的时候,数据库自动会根据分区字段的值,将数据插入到相应的分区中,hive也提供了类似的机制,即动态分区,只不过,使用hive的动态分区需要进行相应的配置
4.合理设置map及reduce数
问题1:通常情况下,作业会通过input的目录产生一个或多个map任务
- 主要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小
问题2:是不是map数越多越好?
- 答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当作一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费,而且,同时可执行的map数是受限的
问题3:是不是保证每个map处理接近128m的文件块,就高枕无忧了?
- 不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时
针对上面的问题2和问题3,我们需要采取两种方式来解决:减少map数和增加map数
5.并行执行
- hive会将一个查询转化成一个或者多个阶段,这样的阶段可以是MapReduce阶段,抽样阶段,合并阶段,limit阶段,或者hive执行过程中可能需要的其他阶段。默认情况下,hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么job可能就越快完成
6.严格模式
严格模式可以防止用户执行那些可能意想不到的不好的影响的查询
- 对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速,没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表
- 对于使用了order by语句的查询,要求必须使用limit语句。因为order by为了执行排序过程会将所有的结果数据分发到同一个reducer中进行处理,强制要求用户增加这个limit语句可以防止reducer额外执行很长一段时间
- 限制笛卡尔积查询。对关系型数据库非常了解的用户可能期望在执行join查询的时候不使用on语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将where语句转化成on语句。不幸的是,hive并不会执行这样的优化,因此,如果表足够大,那么这个查询就会出现不可控的情况
7.JVM重用
- JVM重用是hadoop调优参数的内容,其对hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短
- hadoop默认配置通常是使用功能派生JVM来执行map和reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次,N的值可以在hadoop的mapredsite.xml文件中进行配置,通常在10-20之间,具体多少需要根据具体业务场景测试得出
- 这个功能的缺点是:开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。如果某个不平衡的job中有某几个reduce task执行的时间要比其他reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放
8.推测执行
- 在分布式集群环境下,因为程序bug(包括hadoop本身的bug),负载不均衡或者资源分布不均等原因,会造成同一个作业的多个任务之间运行速度不一致,有些任务的运行速度可能明显慢于其他任务,则这些任务会拖慢作业的整体执行速度。为了避免这种情况发生,hadoop采用了推测执行机制,它根据一定的法则推测出拖后腿的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果
- 关于调优这些推测执行变量,还很难给一个具体的建议。如果用户对于运行时的偏差非常敏感的话,那么可以将这些功能关闭掉,如果用户因为输入数据量很大而需要执行长时间的map或者reduce task的话,那么启动推测执行造成的浪费是非常巨大的