Hive 分区表

Hive分区表

分区表的概念、创建

当 Hive 表对应的数据量大、文件多时,为了避免查询时全表扫描数据,Hive 支持根据用户指定的字段进行分区,分区的字段可以是日期、地域、种类等具有标识意义的字段。

比如把一整年的数据根据月份划分12个月(12个分区),后续就可以查询指定月份分区的数据,尽可能避免了全表扫描查询。

image-20211114170859680

分区表建表语法

1
CREATE TABLE table_name (column1 data_type, column2 data_type) PARTITIONED BY (partition1 data_type, partition2 data_type,….);

需要注意:分区字段不能是表中已经存在的字段,因为分区字段最终也会以虚拟字段的形式显示在表结构上。

分区表数据加载–静态分区

所谓静态分区指的是分区的字段值是由用户在加载数据的时候手动指定的。

语法如下:

1
load data [local] inpath ' ' into table tablename partition(分区字段='分区值'...);

Local表示数据是位于本地文件系统还是HDFS文件系统。

静态加载数据操作如下,文件都位于Hive服务器所在机器本地文件系统上。

image-20211114171034040

1
2
3
4
5
6
load data local inpath '/root/hivedata/archer.txt' into table t_all_hero_part partition(role='sheshou');
load data local inpath '/root/hivedata/assassin.txt' into table t_all_hero_part partition(role='cike');
load data local inpath '/root/hivedata/mage.txt' into table t_all_hero_part partition(role='fashi');
load data local inpath '/root/hivedata/support.txt' into table t_all_hero_part partition(role='fuzhu');
load data local inpath '/root/hivedata/tank.txt' into table t_all_hero_part partition(role='tanke');
load data local inpath '/root/hivedata/warrior.txt' into table t_all_hero_part partition(role='zhanshi');

分区表数据加载–动态分区

往 Hive 分区表中插入加载数据时,如果需要创建的分区很多,则需要复制粘贴修改很多 SQL 去执行,效率低。因为 Hive 是批处理系统,所以 Hive 提供了一个动态分区功能,其可以基于查询参数的位置去推断分区的名称,从而建立分区。

所谓动态分区指的是分区的字段值是基于查询结果自动推断出来的。核心语法就是 insert+select

启用 Hive 动态分区,需要在 Hive 会话中设置两个参数:

1
2
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;

第一个参数表示开启动态分区功能,第二个参数指定动态分区的模式。分为 nonstick非严格模式和strict严格模式。strict 严格模式要求至少有一个分区为静态分区。

创建一张新的分区表 t_all_hero_part_dynamic

1
2
3
4
5
6
7
8
9
10
11
12
13
create table t_all_hero_part_dynamic(
id int,
name string,
hp_max int,
mp_max int,
attack_max int,
defense_max int,
attack_range string,
role_main string,
role_assist string
)
partitioned by (role string)
row format delimited fields terminated by "\t";

执行动态分区插入

1
insert into table t_all_hero_part_dynamic partition(role) select tmp.*,tmp.role_main from t_all_hero tmp;

动态分区插入时,分区值是根据查询返回字段位置自动推断的。

分区表的本质

外表上看起来分区表好像没多大变化,只不过多了一个分区字段。实际上在底层管理数据的方式发生了改变。

非分区表:t_all_hero

image-20211114171303947

分区表:t_all_hero_part

image-20211114171313226

image-20211114171321468

分区的概念提供了一种将 Hive 表数据分离为多个文件/目录的方法。不同分区对应着不同的文件夹,同一分区的数据存储在同一个文件夹下。只需要根据分区值找到对应的文件夹,扫描本分区下的文件即可,避免全表数据扫描。

分区表的使用

分区表的使用重点在于:

  • 建表时根据业务场景设置合适的分区字段。比如日期、地域、类别等;
  • 查询的时候尽量先使用where进行分区过滤,查询指定分区的数据,避免全表扫描。

比如:查询英雄主要定位是射手并且最大生命大于6000的个数。使用分区表查询和使用非分区表进行查询,SQL如下:

1
2
3
4
5
--非分区表 全表扫描过滤查询
select count(*) from t_all_hero where role_main="archer" and hp_max >6000;

--分区表 先基于分区过滤 再查询
select count(*) from t_all_hero_part where role="sheshou" and hp_max >6000;

分区表的注意事项

  1. 分区表不是建表的必要语法规则,是一种优化手段表,可选;
  2. 分区字段不能是表中已有的字段,不能重复;
  3. 分区字段是虚拟字段,其数据并不存储在底层的文件中;
  4. 分区字段值的确定来自于用户价值数据手动指定(静态分区)或者根据查询结果位置自动推断(动态分区
  5. Hive支持多重分区,也就是说在分区的基础上继续分区,划分更加细粒度

多重分区表

通过建表语句中关于分区的相关语法可以发现,Hive支持多个分区字段:PARTITIONED BY (partition1 data_type, partition2 data_type,….)

多重分区下,分区之间是一种递进关系,可以理解为在前一个分区的基础上继续分区。从HDFS的角度来看就是文件夹下继续划分子文件夹。比如:把全国人口数据首先根据省进行分区,然后根据市进行划分,如果需要甚至可以继续根据区县再划分,此时就是3分区表。

1
2
3
4
5
6
7
8
-单分区表,按省份分区
create table t_user_province (id int, name string,age int) partitioned by (province string);

--双分区表,按省份和市分区
create table t_user_province_city (id int, name string,age int) partitioned by (province string, city string);

--三分区表,按省份、市、县分区
create table t_user_province_city_county (id int, name string,age int) partitioned by (province string, city string,county string);

多分区表的数据插入和查询使用

1
2
3
load data local inpath '文件路径' into table t_user_province partition(province='shanghai');
load data local inpath '文件路径' into table t_user_province_city_county partition(province='zhejiang',city='hangzhou',county='xiaoshan');
select * from t_user_province_city_county where province='zhejiang' and city='hangzhou';

Hive 分区表
https://flepeng.github.io/045-Hive-21-命令-Hive-分区表/
作者
Lepeng
发布于
2025年1月21日
许可协议