hive与Oracle

本文深入探讨了Hive的底层逻辑,包括GROUP BY、JOIN、COUNT(DISTINCT)的处理,以及数据倾斜的场景与解决方案。详细介绍了Hive的调优策略,如建表优化、SQL优化、架构调优,涉及到分区、分桶、存储格式和压缩等方面。同时,对比了Hive与Oracle的差异,包括两者在存储、计算、SQL语法和功能上的区别。
摘要由CSDN通过智能技术生成

一、hive底层逻辑  

 GROUP BY 原理

  select name,count(num) from tb group by name

map 阶段,将 group by 后的字段组合作为 key,如果 group by 单字段那么 key 就一个。
将 group by 之后要进行的聚合操作字段作为值,如要进行 count,则 value 是 1;如要 sum 另一个字段,则 value 就是该字段。
shuffle 阶段,按照 key 的不同分发到不同的 reducer。注意此时可能因为 key 分布不均匀而出现数据倾斜的问题。
reduce 阶段,将相同 key 的值累加或作其他需要的聚合操作,得到结果。

JOIN原理 

 

count(distinct) 原理

select num,count(distinct name) as count_name from tb 

 

MapReduce过程详解及其性能优化

Hadoop作业称为Job,Job分为Map、Shuffle和Reduce阶段,MAP和Reduce的Task都基于JVM进程运行的。
MAP阶段:从HDFS读取数据,split文件产生task,通过对应数量的Map处理,map输出的每一个键值对通过key的hash值计算一个partition,数据通过环形缓冲区,sort、spill、merge生成data和index文件;
Reduce阶段:reduce通过Shuffle Copy属于自己的那部分数据,然后sort、spill、merge形成一个大文件,调用reduce函数进行处理.

二、数据倾斜场景以及解决方法

常见的数据倾斜场景有group by , join , count(distnct)

1  group by

原因:默认情况下,map阶段相同的 key 会分发到同一个reduce 端聚合,热点 key 导致 group by 聚合倾斜

解决办法:

---开启map 端聚合: set  hive.map.merge.aggr= true; 一般是默认开启 ,减少数据传输及在reduce阶段的处理时间.       

set hive.groupby.mapaggr.checkinterval=10000; 设置在map端聚合操作的条数.当大于该值时才会在map端聚合

---开启负载均衡:  set hive.groupby.skewindata=true; 该设置会在数据出现倾斜时,将一个group by 的执行计划拆分成2个阶段MR,第一个阶段将key 随机分发到不同的reduce进行聚合,如何第二阶段MR会基于前一阶段预处理的结果,将相同的key分发到同一个reduce算子,执行聚合操作

---小文件过多时,合并小文件: set hive.merge.mapredfiles=true;

2  join 

a .小表 join 大表

原因:主要是热点key 导致,在shuffle 过程中,相同的key 会基于hash 分发到同一个 reduce 算子上,导致join 倾斜

解决办法:

---开启map 端 join: set  hive.auto.convert.join=true; 一般默认是打开的

开启mapjoin后,join时会在map端将小表缓存到内存中(缓存为hash table) ,在map 端执行 join.

小表默认是1000行或者25MB大小,可以设置参数提高小表的阈值:  

set hive.mapjoin.smalltable.filesize=25000000;

b 大表 join 大表

原因:跟大表join 下表倾斜原因差不多,存在热点key ,或者大量无用的空key,导致倾斜

解决办法:

---运行时优化: set hive.optimize.skewjoin=true; 开启倾斜关联开启对倾斜数据join的优化

设置join 倾斜阈值: set hive.skewjoin.key=100000; 当join对应的key记录的条数超过10000,就可以人为这个key 发生了数据倾斜,会对其进行分拆优化

---编译时优化: set hive.optimize.skewjoin.compiletime=true; 可以在编译SQL时将计划优化完成,但是需要在建表时指定数据倾斜元数据信息

---union 优化: set hive.optimize.union.remove=true;

一般情况下,这三种优化都要同时开启

 除了以上参数外,还可以通过 子查询剔除空key, 空key 转为随机字符串,大表拆分成小表 ,分别join 再 union 等方式进行优化

3 count(distinct) 

原因:所有key 会分发到同一个reduce 进行去重统计个数,数据量较大时会导致运行时间过长 

解决办法:改成group by

SELECT COUNT(DISTINCT id)
FROM table;
改成
SELECT COUNT(t1.id) 
FROM ( SELECT id 
       FROM tabe
       GROUP BY id
      ) t1
;

补充:4 map和reduce 

原因1:当出现小文件时,需要合并小文件

 解决办法:

reduce端输出合并: set hive.merge.mapredfiles=true;

原因2:输入数据存在大块和小块的严重问题

解决办法:

任务输入前做文件合并,将小文件合并成大文件: set hive.merge.mapredfiles=true;

原因3:单个文件大小稍大于配置的block 块的大小

解决办法:

此时需要增加map task的个数: set mapred.map.tasks=25;

原因4:文件大小适中,但是map端计算量非常大

解决办法:

增加map和reduce个数:set mapre.map.tasks=250;

                                     set mapre.reduce.tasks=250;

三、hive调优 

1.建表优化

 a 分区优化

建分区表,使用这个字段做分区字段,在查询的时候,使用分区字段来过滤就可以避免全表扫描,只需要扫描这张表的一个分区的数据即可

1.分区表定义

分区表实际上就是对应一个hdfs文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件.hive中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集,在查询时通过where子句中的表达式选择查询所需要的指定的分区,这样查询效率会提高很多.(谓词下推)

表分区就是会在表目录下面针对不同的分区创建一个子目录,如果有二级分区,那么会在一级子目录下面计息创建子目录.hive中的分区字段是表外字段,mysql中的分区字段是表内字段

2.创建分区表语法

create table dept_partition(deptno int,dname string,loc string)
partitioned by (month string)---按月分组
row format delimited fields

 分区字段是 month,分区的数据类型是string,分区字段不能是表里的字段 

3.创建二级分区语法

create table dept_partition(deptno int,dname string,loc string)
partitioned by (month string,year string)---按月和年分组
row format delimited fields
create table if not exists employee_partitioned (
  `name` string,
  `employee_id` int,
  `number` string)
partitioned by (
  `year` int,
  `month` int)
row format delimited fields terminated by '|'
stored as textfile;

year 为一级分区,month为二级分区 

4.静态分区与动态分区

4.1 静态分区(默认)

4.1.1静态分区创建表

create table ods_users(
userid string,
username string,
birthday string,
sex string 
)
row format delimited fields terminated by ',' 
location '/pw';

4.1.2静态分区操作:增加或删除分区语法 

-- 创建分区
//单个分区创建
alter table employee_partitioned add partition(year='2019',month='6') ;
//多个分区创建
alter table employee_partitioned add partition(year='2020',month='6') partition(year='2020',month='7');
-- 删除分区
//单个分区删除
alter table employee_partitioned drop partition (year='2019',month='6');
//多个分区删除
alter table employee_partitioned partition (year='2020','month=6'), partition (year='2020',month='7');

4.1.3静态分区加载插入数据

load data local inpath '/文件路径' into  table '表名' partition'(分区信息)' 

hive> load data local inpath '/usr/local/wyh/test_data/user_partition1.txt' 
into table part-demo1 partition(testdate='2022-04-28');

-- 静态分区加载二级分区

load data local inpath '/文件路径' into  table '表名' partition'(分区信息1,分区信息2)'

hive> load data local inpath '/usr/local/wyh/test_data/user_partition2.txt' 
into table part_demo2 partition(year='2022',month='03');

静态分区加载插入数据 

insert into 将数据添加到表中
insert overwrite 会覆盖表中已有的数据

insert into userinfos partition(sex='male') 
select userid,username,birthday from ods_users where sex='male';

insert into userinfos partition(sex='female') 
select userid,username,birthday from ods_users where sex='female';
//将本地文件传入hdfs中
Hadoop dfs -put /data/employee_hr.txt /tmp/employee
//将文件映射为相应的表
create table if not exists employee_hr(
    name string,
    employee_id int,
    number string,
    start_date date)
    row format delimited fields terminated by '|'
    location '/data/employee_hr.txt';

//根据查询所得的结果传入相应的文件夹中
insert overwrite table employee_partitioned  partition(year=2020,month=8)
select name,employee_id,number from employee_hr 
where year(start_date)=2020 and month(start_date)=8;

4.2动态分区

4.2.1开启动态分区

动态分区默认是没有开启。开启后默认是以严格模式执行的,在这种模式下需要至少一个分区字段是静态的

关闭严格分区模式

动态分区模式时是严格模式,也就是至少有一个静态分区。
        set hive.exec.dynamic.partition.mode=nostrict    //分区模式,默认nostrict
        set hive.exec.dynamic.partition=true            //开启动态分区,默认true
        set hive.exec.max.dynamic.partitions=1000        //最大动态分区数,默认1000 

        set hive.exec.max.dynamic.partitions.pernode =100 :单个节点上的mapper/reducer允许创建的最大分区

strict:最少需要有一个是静态分区

nostrict:可以全部是动态分区

 4.2.2动态分区的操作

 (1)开启动态分区功能(默认true,开启)
set hive.exec.dynamic.partition=true
(2)设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
set hive.exec.dynamic.partition.mode=nonstrict
(3)在所有执行MR的节点上,最大一共可以创建多少个动态分区。默认1000
set hive.exec.max.dynamic.partitions=1000
(4)在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
set hive.exec.max.dynamic.partitions.pernode=100
(5)整个MR Job中,最大可以创建多少个HDFS文件。默认100000
set hive.exec.max.created.files=100000
(6)当有空分区生成时,是否抛出异常。一般不需要设置。默认false
set hive.error.on.empty.partition=false

4.2.2创建动态分区表 

create table if not exists dyp1

(uid int,

commentid bigint,

recommentid bigint)

partitioned by(year int,month int,day int)

row format delimited fields terminated by '\t';
create table myusers( 
userid string,
username string,
birthday string
) 
partitioned by (sex string)
row format delimited fields terminated by ','
 stored as textfile;

--创建临时表 

create table if not exists tmp
(uid int,
commentid bigint,
recommentid bigint,
year int,
month int,
day int)
row format delimited fields terminated by '\t';

 4.2.3动态分区加载数据 

load data local inpath '/root/Desktop/comm' into table tmp;

4.2.4插入数据(不指定分区值,该字段相同值就会分为一个分区) 

insert into myusers partition(sex) select * from ods_users;

 --严格模式动态分区插入数据

insert into table dyp1 partition(year=2016,month,day)

select uid,commentid,recommentid,month,day from tmp;

 --为非严格模式动态分区插入数据

insert into table dyp2 partition(year,month,day)

select uid,commentid,recommentid,year,month,day from tmp;

5.静态分区和动态分区的区别及应用场景 

 5.1静态分区和动态分区的区别(静态分区的列是在编译时期,通过用户传递来决定的;动态分区只有在SQL执行时才能决定)

静态分区 动态分区
①静态分区是在编译期间指定的指定分区名 ①根据分区字段的实际值,动态进行分区
②支持load和insert两种插入方式 ②是在sql执行的时候进行分区
load方式
会将分区字段的值全部修改为指定的内容
一般是确定该分区内容是一致的时候才会使用
③需要先将动态分区设置打开
insert方式
必须先将数据放在一个没有设置分区的普通表中
该方式可以在一个分区内存储一个范围的内容
从普通表中选出的字段不能包含分区字段
④只能用insert方式
③适用于分区数少,分区名可以明确的数据 ⑤通过普通表选出的字段包含分区字段,分区字段放置在最后,多个分区字段按照分区顺序放置

5.2静态分区与动态分区的应用场景

静态分区:适合已经确认分区的文件,分区相对较少的,适合增量导入的应用场景

动态分区:适合根据时间线做分区,分区比较多的,适合全量导入的场景

6.查看分区

show table dept_partition;

7.显示分区

show partitions iteblog; 

7.删除分区

alter  table dept_partition drop partition(month='2017-07') ,
partition(month='2017-08') ,
partition(month='2017-09');----注意逗号

8.增加分区         

alter  table dept_partition 
add partition(month='2017-07') 
partition(month='2017-08') 
partition(month='2017-09');---直接空格,没有逗号

 9.修改分区

ALTER TABLE iteblog PARTITION (dt='2008-08-08') 
SET LOCATION "new location";

ALTER TABLE iteblog PARTITION (dt='2008-08-08') 
RENAME TO PARTITION (dt='20080808');

10.修复分区

修复分区就是重新同步hdfs上的分区信息

msck repair table userinfos;

11.分区表的注意事项

--让分区表和数据产出关联的三种方式

先创建hdfs目录,再上传文件,然后刷新分区表的元数据(MSCK REPAIR TABLE 表名) 

 先创建hdfs目录,再上传文件,然后创建分区(alter table 表名 add partition。。。)

先创建hdfs目录,然后通过load语句加载数据文件。 

 --分区注意细节

(1)、尽量不要用动态分区,因为动态分区的时候,将会为每一个分区分配reducer数量,当分区数量多的时候,reducer数量将会增加,对服务器是一种灾难。

(2)、动态分区和静态分区的区别,静态分区不管有没有数据都将会创建该分区,动态分区是有结果集将创建,否则不创建。

(3)、hive动态分区的严格模式和hive提供的hive.mapred.mode的严格模式。

b 分桶优化


​​​​​​​

#创建分桶表
create table stu_buck(id int, name string)
clustered by(id) 
into 4 buckets
row format delimited fields terminated by '\t';#创建中间表create table stu(id int, name string)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值