1 分区表
1.1 Hive查询基本原理
Hive的设计思想是通过元数据将HDFS上的文件映射成表,基本的查询原理是当用户通过HQL语句对Hive中的表进行复杂数据处理和计算时,默认将其转换为分布式计算MapReduce程序对
HDFS中的数据进行读取处理的过程。
例如,当我们在Hive中创建一张表tb_login并关联HDFS上的文件,用于存储所有用户的登录信
息,当我们对这张表查询数据时,Hive中的实现过程如下:
⚫ step1:创建表
--创建数据库 create database tb_part; --创建表 create table tb_login( userid string, logindate string ) row format delimited fields terminated by ' '\t' ';
◼ HDFS中自动在Hive数据仓库的目录下和对应的数据库目录下,创建表的目录
⚫ step2:关联数据
load data local inpath '/export/data/login.log' into table tb_login;
◼ 数据会被自动放入HDFS中对应的表的目录下
◼ 数据在表中可以被正常读取
⚫ step3:查询数据
-- 统计3月24号的登录人数 select logindate, count(*) as cnt from tb_login where logindate = '2021- - 03- - 24' group by logindate;
◼ 当执行查询计划时,Hive会使用表的最后一级目录作为底层处理数据的输入
◼ 先根据表名在元数据中进行查询表对应的HDFS目录
◼ 然后将整个HDFS中表的目录作为底层查询的输入,可以通过explain命令查看执行计
划依赖的数据
explain extended select logindate, count ( * ) as cnt from tb_login where logindate = '2021- - 03- - 24' group by logindate;
1.2 普通表结构问题
默认的普通表结构中,表的最后一级目录就是表的目录,而底层的计算会使用表的最后一级目录作为Input进行计算,这种场景下,我们就会遇到一个问题,如果表的数据很多,而我们需要被
处理的数据很少,只是其中一小部分,这样就会导致大量不必要的数据被程序加载,在程序中被过
滤,导致大量不必要的计算资源的浪费。
例如,上面的需求中,只需要对2021-03-24日的数据进行计算,但实际上由于表结构的设计,
在底层执行MapReduce时,将整张表的数据都进行了加载,MapReduce程序中必须对所有数据进
行过滤,将3月24号的数据过滤出来,再进行处理。假设每天有1G的数据增量,一年就是365GB的
数据,按照业务需求,我们每次只需要对其中一天的数据进行处理,也就是处理1GB的数据,程序
会先加载365GB的数据,然后将364GB的数据过滤掉,只保留一天的数据再进行计算,导致了大量
的磁盘和网络的IO的损耗。
1.3 分区表设计思想
针对上面的问题,Hive提供了一种特殊的表结构来解决——分区表结构。分区表结构的设计思
想是:根据查询的需求,将数据按照查询的条件【一般都以时间】进行划分分区存储,将不同分区
的数据单独使用一个HDFS目录来进行存储,当底层实现计算时,根据查询的条件,只读取对应分
区的数据作为输入,减少不必要的数据加载,提高程序的性能。
例如,上面的需求中,我们可以将每天的用户登录数据,按照登陆日期进行分区存储到Hive
表中,每一天一个分区,在HDFS的底层就可以自动实现将每天的数据存储在不同的目录中,当用
户查询某天的数据时,可以直接使用这一天的分区目录进行处理,不需要加载其他数据。
1.4 分区表测试
基于分区表的设计实现将所有用户的登录信息进行分区存储
⚫ 创建分区表:按照登陆日期分区
–创建表
create table tb_login_part(
userid string
)
partitioned by (logindate string)
row format delimited fields terminated by ’ ‘\t’ ';
row format delimited fields terminated by ’ ‘\t’ ';
⚫ 将所有登陆数据写入分区表,分区存储
–开启动态分区
set hive.exec.dynamic.partition.mode=nonstrict;
–按登录日期分区
insert into table tb_login_part partition(logindate)
select * from tb_login;
◼ HDFS中会自动在表的目录下,为每个分区创建一个分区目录
⚫ 查询2021-03-23或者2021-03-24的数据进行统计
select
logindate,
count ( * ) as cnt
from tb_login_part
where logindate = ‘2021- - 03- - 23’ or logindate = ‘2021- - 03- - 24’
group by logindate;
◼ 查询先检索元数据,元数据中记录该表为分区表并且查询过滤条件为分区字段,所以
找到该分区对应的HDFS目录
◼ 加载对应分区的目录作为计算程序的输入
⚫ 查看执行计划
◼ 如果不做分区表
explain extended
select
logindate,
count ( * ) as cnt
from tb_login
where logindate = ‘2021- - 03- - 23’ or logindate = ‘2021- - 03- - 24’
group by logindate;
◼ 如果做了分区表
explain extended
select
logindate,
count ( * ) as cnt
from tb_login_part
where logindate = ‘2021- - 03- - 23’ or logindate = ‘2021- - 03- - 24’
group by logindate;