Hive中支持的分区类型有两种:
两者的区别:
主要在于静态分区需要手动指定,而动态分区是基于查询参数的位置去推断分区的名称,从而建立分区。总的来说就是,静态分区的列是在编译时期通过用户传递来决定的;动态分区只有在SQL执行时才能确定。
下面举例详细说明:
一、静态分区(static partition)
1、静态分区-单分区
1)创建静态分区表t1并向表中导入test.txt文件中的测试数据
create table t1(
id int,
name string,
likes array<string>,
adress map<string,string>
)
partitioned by (department string)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
lines terminated by '\n';
001,Ace,study,Guangdong:SZ,
002,Jack,reading-movie,Guangdong:GG-Guangdong:DG,
003,Maria,basketball-Computer games-Swimming,Guangdong:SZ-Guangdong:DG,
004,Jimmy,reading-sing,Guangdong:SZ-Guangdong:HZ-Guangdong:DG,
005,Tom,dance-movie,Guangdong:FS-Guangdong:DG
查看t1表的分区情况:
查看t1表中的数据:
查看web界面:
如上图可见,在新建分区表的时候,系统会在hive数据仓库默认路径/user/hive/warehouse/库名.db/下创建一个目录(表名),然后在该目录下再创建子目录department=dept-1(分区名),最后在分区名下存放实际的数据文件(load加载进表的文件test.txt)。
我们再导入一组数据到新的part2分区:
查看web界面:
2、静态分区-多分区
创建多分区表t2并向表中导入test.txt文件中的测试数据,分区逻辑大致是部门分区下有性别分区 目录: department/sex
create table t2(
id int,
name string,
likes array<string>,
adress map<string,string>
)
partitioned by (department string,sex string)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
lines terminated by '\n';
查看t2表中的数据:
查看web界面:
注意:分区字段都要加,否则会报错
二、动态分区(dynamic partition)
那么问题来了,在往hive分区表中插入数据时,如果需要创建的分区很多,比如要以表中某个字段进行分区存储,则需要复制粘贴修改很多sql去执行,如此一来效率会很低。
在关系型数据库中,对分区表Insert数据时候,数据库自动会根据分区字段的值,将数据插入到相应的分区中,因为hive是批处理系统,所以hive提供了一个动态分区功能,其可以基于查询参数的位置去推断分区的名称,从而建立分区。
下面我们以一个案例来演示一下:
1、多个分区字段时,全部实现动态分区插入数据
(因为单分区比较简单,这里我们以多分区为例)
1)创建一个测试用表t3并向该表导入测试数据:
create table t3(
id int,
name string,
age int,
gender string,
likes array<string>,
address map<string,string>
)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
lines terminated by '\n';
2)创建目标表t4(该表具有两个分区字段age和gender)
create table t4(
id int,
name string,
likes array<string>,
address map<string,string>
)
partitioned by (age int,gender string)
row format delimited
fields terminated by ','
collection items terminated by '-'
map keys terminated by ':'
lines terminated by '\n';
3)采用动态方式加载数据到目标表t4,加载之前先开启动态分区参数设置不然会报错:
hive> set hive.exec.dynamic.partition=true; //开启动态分区功能(默认true,开启)
hive> set hive.exec.dynamic.partition.mode=nonstrict; //设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
hive> insert into table t4 partition(age,gender) select id,name,likes,address,age,gender from t3;
要点:
因为目标表t4表中只有4个字段(id、name、likes、address),在当我们从t3表查询了6个字段时(多了最后两个age、gender字段),所以系统会默认以最后两个字段age、gender为分区名,因为t4分区表的两个分区字段默认也是该表中的字段,且依次排在表中字段的最后面。在分区时需要分区的字段只能放在后面,不能把顺序弄错。如果我们查询了7个字段的话,则会报错,因为t4表加上两个分区字段也才6个字段。要注意系统是根据查询字段的位置推断分区名的,而不是字段名称。
需要注意的是,在使用insert…select 往表中导入数据时,查询的字段个数必须和目标的字段个数要相同,不能多,也不能少,否则会报错。但是如果字段的类型不一致的话,则会使用null值填充,不会报错。而使用load data形式往hive表中装载数据时,则不会检查。如果字段多了则会丢弃,少了则会null值填充。同样如果字段类型不一致,也是使用null值填充。
查看可知,hive已经完成了以age和gender两个字段为分区字段,实现了动态分区:
查看目标表t4中的数据:
2、多个分区字段时,实现半自动分区
(部分字段静态分区,注意静态分区字段要在动态的前面)
1) 创建一个只有一个字段,具有两个分区字段的分区表t5
2) 准备测试用表t0
3)往目标表t5分区表中以半动态分区方式插入测试用表t0中的数据
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
insert overwrite table t5 partition(country='china',city) select id ,city from t0;
#country分区为静态,city为动态分区,以查询的city字段为分区名
4) 查询结果显示:
另外,一些与动态分区相关的其它优化参数:
(1)在所有执行MR的节点上,最大一共可以创建多少个动态分区。
hive.exec.max.dynamic.partitions=1000
(2)在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
hive.exec.max.dynamic.partitions.pernode=100
(3)整个MR Job中,最大可以创建多少个HDFS文件。
hive.exec.max.created.files=100000
(4)当有空分区生成时,是否抛出异常。一般不需要设置。
hive.error.on.empty.partition=false