hive数据仓库之笔记

文章目录

  • 基本操作
    • hive 操作
    • 数据库操作
    • 表操作
    • hive 的临时参数设置
  • 基本数据类型
    • 内部表
    • 外部表
    • 内部表&外部表相互转化
    • 内、外部表总结
    • 分区表
  • DML数据操作
    • 数据导入
      • load
      • as 查询加载
      • insert into 追加,插入
      • location加载
      • import
    • 数据导出
      • insert 导出
      • hdfs dfs -get
      • hive shell 导出
      • Export
  • 查询
  • 排序
  • 行转列
  • 列转行
  • 窗口函数
    • RANK() & ROW_NUMBER()& DENSE_RANK()
  • 自定义函数 UDF
  • 虚拟列
  • 压缩
    • 压缩格式与 hive 命令
    • 压缩配置
  • 调优
    • Fetch 抓取
    • hive 本地模式
    • 表的优化
      • 小表,大表 join
      • 大表,大表 join
        • 空 key 过滤
        • key 转换
        • mapJoin
        • group by
        • count(distinct)去重统计
        • 笛卡尔积
        • 行列过滤
        • 动态分区调整
    • 数据倾斜
      • 设置合理 map 数
      • 小文件合并
      • 复杂文件增加 map 数
      • 设置合理 reduce 数
    • 并行执行
    • 严格模式
    • jvm 重用
    • 推测执行

基本操作

hive 操作

# 启动 hive
./bin/hive
 # 如果启动失败,可以是因为 hive service 需要启动,需要先执行该命令
./bin/hive  --service metastore & 

# 帮助
./bin/hive --help

# 指定默认连接的数据库
 hive --database dbName  
 eg:hive --database db01

// 在 linux 终端中执行 SQL 或者 HQL 语句
hive -e '命令'
eg: hive -e 'show databases'

# 在 linux shell 命令中执行一个写有 SQL 语句的文件
hive -f /opt/app/hive.sql (hive.sql是sql语句文件)

# 使当前 shell 配置临时生效
hive --hiveconf hive.cli.print.current.db=false

数据库操作

# 查看数据库
show databases;

# 使用数据库
use dbName

# 创建 db01 数据库
create database if not exists dbName; 

# 在 hdfs 上指定目录 “dblocate” 来数据库的目录
create database if not exists dbName LOCATION '/dblocate';  
如果不指定目录,那么数据库的目录为:hdfs: /user/hive/warehouse/。这也是 hive 创建数据库的默认存储路径。

# 删除数据库
drop database dbName [cascade]

# 删除表
drop table tbName;

# 查看表描述信息
desc tableName

# 查看内置函数
show functions

# 查看函数描述
desc function methodName;

表操作

# 建表之前需要指定数据库
use  databaseName;

#  与 mysql 一样,创建一个 student 的表,包括两个字段: num,name
create table if not exists student(
     num int,
     name string
)ROW FORMAT DELIMITED FIELDS TERMINATED
 BY '\t'  # 申明文件分隔符
 stored as textfile;  申明文件存储格式。
 
# 复制表结构,生成一张新的空表
create table cpTable like tbName; 

# 复制结果临时表,生成一张有数据的新表。
 create table cpTable as select name from tbName; 

# 删除表
drop table if exists tbName;

# 清空表内容, 但保留表结构
truncate table tbName;

# 查看表
show tables in dbName;

# 修改表的名称
alter table oldTableName rename to newTableName;

# 增加列
alter table tableName add columns(col type);

# 替换全部的列
alter table tableName replace columns(col1 type1, col2 type2, col3 type3);

# 修改列
alter table tableName change oldColName newColName columnType;

# 加载数据
【overwrite,覆盖重写,之前的 hive 的数据不存在被覆盖了】
【local 表示从本地路径。去掉 local,数据时从 hdfs 上加载】
load data local inpath '/opt/datas/student.txt' [overwrite] into table tb01;
load data inpath '/student.txt' into table student;
【如果 tb 是内部表,那么数据需要先被加载到 hdfs 上,然后在被移动到 hive 表中对应的位置。】

hive 的临时参数设置

【仅对本次hive启动有效】
set hive.cli.print.current.db=true;  # 显示当前数据库名 
set hive.cli.print.header=true  # 显示表头
set -v     # 显示所有设置

# 查看本地目录信息
 hive -> !ls /;  (hive 终端)

# 查看 HDFS 目录信息
 hive -> dfs -ls / ;

基本数据类型

数据类型 长度 范围 示例
Tinyint 1字节的整数 -128 ~ 127 12
SmallInt 2字节的整数 -32768 ~ 32767 255
Int 4字节的整数 -2147483648 ~ 2147483647 250000
BigInt 8字节的整数 -9223372036854775808 ~ 9223372036854775807 2500000000
Boolean bool类型 true,false TRUE
Float 4字节单精度浮点型 3.1211
Double 8字节双精度浮点型 3.1123123
String 字符串 “absec”
TimeStamp 时间戳,格式 yyyy-mm-dd hh:mm:ss 支持 unix timestamp 2019-02-03 02:21:39
Binary 二级制 0 or 1
Date 日期,格式 yyyy-mm-dd 可用 String 代替
Decumal 任意精度数字 10
Varchar 字符串 字符串长度只能为 1 ~ 65355 “abcdfs”
Char 字符串 长度 1 ~ 255 “bacdf”

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]

1)【CREATE TABLE】 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。
2)【EXTERNAL】 关键字可以让用户创建一个【外部表】,在建表的【同时指定一个指向实际数据的路径】(LOCATION)。Hive 创建【内部表】时,会将数据【移动】到数据仓库指向的路径;若创建【外部表】,【仅记录数据所在的路径】,不对数据的位置做任何改变。在删除表的时候,【内部表】的【元数据】和【数据】会被【一起删除】,而【外部表】只【删除元数据】,不删除数据。
3)COMMENT:为表和列添加注释。
4)PARTITIONED BY创建分区表。
5)CLUSTERED BY创建分桶表。
6)SORTED BY不常用。
7)ROW FORMAT DELIMITED [FIELDS TERMINATED BY char] 
	                    [COLLECTION ITEMS TERMINATED BY char] 
	                    [MAP KEYS TERMINATED BY char] 
	                    [LINES TERMINATED BY char] 
8)STORED AS指定存储文件类型
	常用的存储文件类型:SEQUENCEFILE(二进制序列文件)、TEXTFILE(文本)、RCFILE(列式存储格式文件)
	如果文件数据是纯文本,可以使用STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
9)LOCATION :指定表在HDFS上的存储位置。
10)LIKE允许用户复制现有的表结构,但是不复制数据。

内部表

内部表是未被 “external” 修饰的表,其由 hive 管理。内部表由于存储了元数据以及存储数据,所以删除内部表,存储数据与元数据也会被删除。并且内部表被创建得路径在 hive 的默认仓库目录,即 “ /user/Hive/warehouse/”

create table student06(
	id int,
    name string,
    age int) row format delimited fields terminated by '\t'  
    stored as textfile 
    location 'hdfs://......'

# 查看基表信息
show create table tbName;

# 查看表格式
desc formatted tbName;

外部表

外部表是被 “external” 修饰的表,其由 HDFS 管理。删除外部表仅仅会删除元数据,但是存储数据不会被删除。用户在创建外部表时,可以自己指定表的路径:

create external table student06(
	id int,
    name string,
    age int)
    row format delimited fields terminated by '\t'
    location 'hdfs://dataPath';
  
  # 导入数据
  load data local inpath '/opt/module/datas/dept.txt' into table default.student06;

内部表&外部表相互转化

1. 内部表转化为外部表
alter table student2 set tblproperties('EXTERNAL'='TRUE');

2. 外部表转化为
alter table student2 set tblproperties('EXTERNAL'='FALSE');

内、外部表总结

内部表 外部表
目录由 hive创建在默认的目录下 目录由用户自己创建表时自己用 location 来指定
删除表时,表的元数据与表的数据目录都会被删除 删除表时,只删除表的元数据而表的数据不会被删除

一般来源的数据会在不同的平台上进行处理,所以为了方便映射,就可以采用【外部表】来进行映射,这样即使删除掉了表,也不会删除数据。也就不会影响数据在其他平台上的操作。

分区表

分区表是在系统下创建文件夹目录,把分类数据放在不同的目录里面,可以加快查询速度。

如: 创建一个以 age 分区的表,

create table student08(
	num int,
    name string
    )PARTITIONED BY (age string) ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";

# 导入分区数据
LOAD DATA INPATH '/stud.txt' OVERWRITE INTO TABLE student08 PARTITION (age='7');
LOAD DATA INPATH '/stud.txt' OVERWRITE INTO TABLE student08 PARTITION (age='10');

# 单分区查询
select * from stundent08 where age = 9;

# 增加表分区, 用空格分开
alter table student08 add partition(age='9') partition(age='15');

# 查看表分区详情
show partition tableName;

# 导入分区数据
insert into student08 partition(age='11') select * from student08 where age='9';

# 删除表分区  --  子目录和数据都会被删除
alter table tableName drop partition(age='11');

分区表中,表目录里面有多个子目录。如果要针对不同时间,格式等要求创建表,那么可以创建分区表。

分区表的数据是存放在不同的子目录中,在查询的时候,既可以针对子目录进行扫描,也可以针对全表进行扫描。

创建分区表后,分区目录看不到子目录,只有在导入数据才可以看到。

DML数据操作

数据导入

load

  1. 导入格式
load data [local] inpath '/opt/module/datas/student.txt' [overwrite] into table student [partition (partcol1=val1,…)];

1)load data:表示加载数据
2)local:表示从本地加载数据到hive表(【复制】);否则从HDFS加载数据到hive表(【移动】)
3)inpath:表示加载数据的路径
4)overwrite into:表示覆盖表中已有数据,否则表示追加
5)into table:表示加载到哪张表
6)student:表示具体的表
7)partition:表示上传到指定分区
  1. 案例
load data local inpath 'local_path' into table tb_name; 
load data inpath 'hdfs_path' into table tb_name;

as 查询加载

# 将从 oldTbName的查询结果保存到 newTbName 上
create table newTbName as select * from oldTbName;

insert into 追加,插入

# 根据查询结果插入到表中
insert into table tbName select * from tb1_name;

# 基本插入数据
insert into table  student partition(age='11') values(1,'wangwu');

# 多数据插入
from student
	insert overwrite table student partition(age='15')
	select id, name where age='10'
	insert overwrite table student partition(age='20')
	select id, name where age='23';

location加载

  1. 将指定的本地文件导入到外部表中,或者管理表中对数据的指定
create table if not exists student5(
              id int, name string
              )
              row format delimited fields terminated by '\t'
              location 'hdfs_table_name';

dfs -put local_file_path hdfs_table_name;

import

import table student2 partition(age='15') from
 '/user/hive/warehouse/export/student';

数据导出

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;
insert overwrite directory '/user/atguigu/student2' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'  select * from student;

hdfs dfs -get

# hdfs dfs -get 在 Linux 控制台操作
[hdfs] dfs -get /user/hive/warehouse/student/month=201709/000000_0 /opt/module/datas/export/student3.txt

hive shell 导出

# Linux 控制台操作
 bin/hive -e 'select * from default.student;' > /opt/module/datas/export/student4.txt;

Export

# 在 hive 控制台操作
export table default.student to '/user/hive/warehouse/export/student';

查询

SELECT [ALL | DISTINCT] select_expr, select_expr, ...
  FROM table_reference
  [WHERE where_condition]
  [GROUP BY col_list]
  [ORDER BY col_list]
  [[CLUSTER BY col_list] | [DISTRIBUTE BY col_list] [SORT BY col_list]]
 [LIMIT number]

排序

  • order by:全局排序
    order by 会对查询的全局结果进行排序。最终 map 数据的数据汇聚到【一个 reduce】 中去执行。如果数据量很大,那么这个操作是相当漫长的。所以在 hive 操作中【尽量少用 order by】,除非数据量很小。

  • sort by : 局部排序
    sort by 是局部排序操作,也就是说在【每个 reduce】 都会进行排序,可以保证每个reduce 中的数据是有序的。但是对于全局而言,其又不一定是有序的。

  • distribute by :根据指定字段分区
    distribute by 是指定输出结果怎样划分到各自的 reduce 分区中。对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。

  • cluster by
    cluster by 具有 sort by 与 distribute by 的两重功能,能将相同字段进行 sort by 排序和distribute by 分区,但是只能倒序排序。

select * from student08 order by age;
select * from student08 sort by age;

set mapreduce.job.reduces=3;
select * from student08 distribute by age sort by name desc;

select * from student08 cluster by age;
select * from  student08 distribute by age sort by age;
# 设置每个 reduce 处理的数据量 
hive.exec.reducers.bytes.per.reduce=

# 设置最大能够运行的 reduce 个数
hive.exec.reducer.max=

# 实际 reduce 的个数
mapreduce.job.reduces=

# 设置 reduce 开启条件
hive.fetch.task.conversion=none,more,min

行转列

CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意个输入字符串;
CONCAT_WS(separator, str1, str2,...):它是一个特殊形式的 CONCAT()。第一个参数是剩余参数间的分隔符。

select name, concat(constellation, ",", blood_type) base from person_info

列转行

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

udtf 包括: split,explode 等 UDTF,将一列数据拆成多行数据。
EXPLODE(col):将hive一列中复杂的array或者map结构拆分成多行

select
    movie,
    category_name
from 
    movie_info lateral view explode(category) table_tmp as category_name;

1. from 加载 movie_info 的表文件,生成一张临时表;
2. lateral view explode 基于from 的临时表,将 category 列数据拆分成多行, 并生成一张临时表。临时表别名为 table_tmp,而新生成的临时表的当前 category 的列名的别名为 category_name;
3. 通过 select 对 lateral view 的临时表进行查询操作。

窗口函数

格式:聚合函数 + over()
OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。不加参数默认全表,和当前行没有关系。

当同一个select查询中存在多个窗口函数时,他们相互之间是没有影响的.每个窗口函数应用自己的规则.

在SQL处理中,窗口函数都是最后一步执行,而且仅位于Order by字句之前。

CURRENT ROW:当前行
n PRECEDING:往前n行数据
n FOLLOWING:往后n行数据
UNBOUNDED:起点,UNBOUNDED PRECEDING 表示从前面的起点, UNBOUNDED FOLLOWING表示到后面的终点
LAG(col,n):往前第n行数据
LEAD(col,n):往后第n行数据
NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型。

2.数据准备: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

3.需求
(1)查询在2017年4月份购买过的顾客及总人数(注意了,不是购买次数)
(2)查询顾客的购买明细及月购买总额
(3)上述的场景,要将cost按照日期进行累加
(4)查询顾客上次的购买时间
(5)查询前20%时间的订单信息

4.创建本地business.txt,导入数据

[atguigu@hadoop102 datas]$ vi business.txt

5.创建hive表并导入数据

create table business(
name string, 
orderdate 
string,cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';

load data local inpath "/opt/module/datas/business.txt" into table business;

6.按需求查询数据
(1)查询在2017年4月份购买过的顾客及总人数

select name,count(*) over () 
from business 
where substring(orderdate,1,7) = '2015-04' 
group by name;

(2)查询顾客的购买明细及月购买总额

select name,orderdate,cost,sum(cost) over(partition by month(orderdate)) from
 business;
select name,orderdate,cost,sum(cost) over(distributed by month(orderdate)) from
 business;

(3)上述的场景,要将cost按照日期进行累加

select name,orderdate,cost, 
sum(cost) over() as sample1,--所有行相加 
sum(cost) over(partition by name) as sample2,--按name分组,组内数据相加 
sum(cost) over(partition by name order by orderdate) as sample3,--按name分组,组内数据累加 
sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row ) as sample4 ,--和sample3一样,由起点到当前行的聚合 
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and current row) as sample5, --当前行和前面一行做聚合 
sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING ) as sample6,--当前行和前边一行及后面一行 
sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 --当前行及后面所有行 
from business;

(4)查看顾客上次的购买时间

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;

(5)查询前20%时间的订单信息

select * from (
    select name,orderdate,cost, ntile(5) over(order by orderdate) sorted
    from business
) t
where sorted = 1;

子查询必须写具体字段,不能用*代替。

RANK() & ROW_NUMBER()& DENSE_RANK()

ROW_NUMBER() RANK() DENSE_RANK()
排序,根据查询出的顺序依次标注排名,没有重复。如 1,2,3 排序,相同数据标注相同的排名,而下一个不同的数据则被跳跃标注。如,1,1,3 排序,相同数据标注相同的排名,下一条不同的数据直接依次标注。如1,1,2
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;

自定义函数 UDF

  1. 配置环境 pom / hive-site.xml
  2. 自定义类继承 org.apache.hadoop.hive.ql.exec.UDF
    实现 public Object evaluate(Object args) 方法
  3. 导出 jar 包并植入本地环境 linux 的 localpath 目录下
  4. 关联 jar。进入hive, add jar localpath;
  5. 创建临时函数 create temperary function 函数名 as ‘包名.类名’;
  6. 执行
public class UserInfoParser extends UDF{
	public String evaluate(String field,int index){
	String replaceAll = field.replaceAll("\\|", " ");
	String[] split = replaceAll.split(" ");
	return split[index-1];
	}
}

// 创建临时函数 
create temporary function functionName as 'packageName.className';

虚拟列

虚拟列并不是在表中真正存在的列,其用意是为了将 hive 中的表进行分区,这对每日增长的海量数据存储而言非常有用的。

其种类有两种:

  1. 这行数据属于哪个文件 ---- INPUT__FILE__NAME
  2. 块的偏移量,类似于每行的存储地址 ---- BLOCK__OFFSET__INSIDE__FILE
select *, INPUT__FILE__NAME from student;
select *, BLOCK__OFFSET__INSIDE__FILE from student;

压缩

Hive 压缩的目的是:减少磁盘 IO 与网络 IO

压缩格式与 hive 命令

zlib       ->      org.apache.hadoop.io.compress.DefaulCodec
gzip       ->      org.apache.hadoop.io.compress.GzipCodec
Bzip2      ->      org.apache.hadoop.io.compress.BZip2Codec
Lzo        ->      com.hadoop.compression.lzo.LzoCodec
Lz4        ->      org.apache.hadoop.io.compress.Lz4Codec
Snappy     ->      org.apache.hadoop.io.compress.SnappyCodec

压缩配置

hive数据仓库之笔记_第1张图片
压缩方案

# MapReduce 配置 map 端压缩:
set mapreduce.map.output.compress=true
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec

# MapReduce 配置 Reduce 端压缩:
set mapreduce.output.fileoutputformat.compress=true
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec

# Hive 配置压缩
set hive.exec.compress.intermediate=true
set mapred.map.output.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
set mapred.output.compression.type=BLOCK

# 任务中间压缩
set hive.exec.compress.intermediate=true
set hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec
set hive.intermediate.compression.type=BLOCK

调优

Fetch 抓取

Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。

可以针对查询进行不执行 MR 来进行处理,参数:hive.fetch.task.conversion = more,表示在 select,where,limit 操作时,都直接进行数据抓取操作,而不涉及 MR 计算的操作,这样执行的效率更快更高。

set hive.fetch.task.conversion= more;

hive 本地模式

对于小数据集,Hive 可以通过本地模式在单台机器上处理所有的任务,执行时间可以明显被缩短。

set hive.exec.mode.local.auto = true    =>  动启动这个优化
set hive.exec.mode.local.auto.inputbytes.max=50000000;    =>   数据大小不能超过 128 MB
set hive.exec.mode.local.auto.input.files.max=10;    =>   mr的最大输入文件个数,默认为 4。

表的优化

小表,大表 join

新版的hive已经对小表JOIN大表和大表JOIN小表进行了优化。小表放在左边和右边已经没有明显区别。

大表,大表 join

空 key 过滤

如果空 key 对应的数据是异常数据,我们需要在SQL语句中进行过滤。

key 转换

有时虽然某个 key 为对应的数据很多,但是相应的数据不是异常数据,必须要包含在 join 的结果中,此时我们可以表 a 中 这个 key 的值赋一个随机的值,使得数据随机均匀地分不到不同的reducer上。

select n.* from nullidtable n full join ori o on 
case when n.id is null then concat('hive', rand()) else n.id end = o.id;

mapJoin

可以用MapJoin把【小表】全部加载到内存在map端进行join,避免reducer处理。

set hive.auto.convert.join = true; 默认为true
set hive.mapjoin.smalltable.filesize=25000000;

select b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from smalltable s
join bigtable  b on s.id = b.id;

group by

并不是所有的聚合操作都需要在Reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在Reduce端得出最终结果。

hive.map.aggr = true  # 是否在Map端进行聚合,默认为True,需要更多的内存
hive.groupby.mapaggr.checkinterval = 100000  # 在Map端进行聚合操作的条目数目
hive.groupby.skewindata = true  # 有数据倾斜的时候进行负载均衡(默认是false)

hive.groupby.skewindata选项设定为 true,生成的查询计划会有两个MR Job。第一个MR Job中,Map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MR Job再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。

count(distinct)去重统计

数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换。

select count(distinct(id) ) from bigtable ;
select count(id) from (select id from bigtable group by id) a;

笛卡尔积

尽量避免笛卡尔积。

行列过滤

谓词下推:先执行where语句
列处理:在SELECT中,只拿需要的列,如果有,尽量使用分区过滤,少用SELECT *。
行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤。

动态分区调整

hive.exec.dynamic.partition=true    # 开启动态分区功能
hive.exec.dynamic.partition.mode=nonstrict   # 设置为非严格模式
hive.exec.max.dynamic.partitions=1000   # 在所有执行MR的节点上,最大一共可以创建多少个动态分区
hive.exec.max.dynamic.partitions.pernode=100   # 在每个执行MR的节点上,最大可以创建多少个动态分区 
hive.exec.max.created.files=100000   # 整个MR Job中,最大可以创建多少个HDFS文件
hive.error.on.empty.partition=false  # 当有空分区生成时,是否抛出异常。一般不需要设置。

数据倾斜

数据倾斜造成的原因:当到达 reduce 端数据如果在某一个 key 上分布特别多的话,就会造成单个节点处理时间异常增多,从而导致整体任务消耗严重。

设置合理 map 数

小文件合并

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

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

复杂文件增加 map 数

set mapreduce.input.fileinputformat.split.maxsize=100;

设置合理 reduce 数

set mapreduce.job.reduces = 15;

并行执行

通过设置参数hive.exec.parallel值为true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。

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

严格模式


    hive.mapred.mode
    strict

  1. 对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表。
  2. 对于使用了order by语句的查询,要求必须使用limit语句。因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止Reducer额外执行很长一段时间。
  3. 限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行JOIN查询的时候不使用ON语句而是使用where语句,这样关系数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况。

jvm 重用


  mapreduce.job.jvm.numtasks
  10

推测执行

 
    hive.mapred.reduce.tasks.speculative.execution
    true
  

你可能感兴趣的:(Hive)