声明:本文为博主参考网上资料整理的文章,未经博主允许不得转载,如有问题,欢迎指正。
分区是hive存放数据的一种方式。将列值作为目录来存放数据,就是一个分区。这样查询时使用分区列进行过滤,只需根据列值直接扫描对应目录下的数据,不扫描其他不关心的分区,快速定位,提高查询效率。hive中支持两种类型的分区:
静态分区SP(static partition)
动态分区DP(dynamic partition)
静态分区与动态分区的主要区别在于静态分区是手动指定,而动态分区是通过数据来进行判断。详细来说,静态分区的列是在编译时期,通过用户传递来决定的;动态分区只有在SQL执行时才能决定。
关系型数据库(如Oracle)中,对分区表Insert数据时候,数据库自动会根据分区字段的值,将数据插入到相应的分区中,Hive中也提供了类似的机制,即动态分区(Dynamic Partition)。
按照常规的方法向分区表中插入数据,如果源数据量很大,那么针对一个分区就要写一个insert,非常麻烦,而且你必须先要知道源数据中都有什么样的数据才能创建分区。例如:
hive> insert overwrite table partition_test partition(stat_date='20110728',province='henan')
select
member_id
,name
from
partition_test_input
where
stat_date='20110728' and province='henan';
使用动态分区可以很好的解决上述问题。动态分区可以根据查询得到的数据自动匹配到相应的分区中去。只不过,使用Hive的动态分区,需要进行相应的配置。
●set hive.exec.dynamic.partition=true;–是否允许动态分区
默认值:false
是否开启动态分区功能,默认false关闭。
使用动态分区时候,该参数必须设置成true。
●set hive.exec.dynamic.partition.mode=nonstrict; --分区模式设置
默认值:strict
动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区。
nonstrict模式:表示允许所有的分区字段都可以使用动态分区。
●set hive.exec.max.dynamic.partitions.pernode=1000;–单个节点上的mapper/reducer允许创建的最大分区
默认值:100
在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。
比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
●set hive.exec.max.dynamic.partitions=1500;–允许动态分区的最大数量
默认值:1000
在所有执行MR的节点上,最大一共可以创建多少个动态分区。
同上参数解释。
●hive.exec.max.created.files=100000;–一个mapreduce作业能创建的HDFS文件最大数
默认值:100000
整个MR Job中,最大可以创建多少个HDFS文件。
一般默认值足够了,除非你的数据量非常大,需要创建的文件数大于100000,可根据实际情况加以调整。
此处补充知识点:使用动态分区可能遇到分区文件数超10万的情况,解决办法参考distribute by控制分区文件数
●hive.error.on.empty.partition=false;–在动态分区插入产生空结果时是否抛出异常
默认值:false
当有空分区生成时,是否抛出异常。一般不需要设置。
创建分区表
create table if not exists partition_test
(
member_id string
,name string
)partitioned by(stat_date string,province string)
;
设置动态分区参数
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
set hive.exec.max.dynamic.partitions.pernode=1000;
set hive.exec.max.dynamic.partitions=1500;
插入数据
动态分区的使用方法很简单,假设我想向stat_date='20110728’这个分区下面插入数据,至于province插入到哪个子分区下面让数据库自己来判断。那可以这样写:
insert overwrite table partition_test partition(stat_date='20110728',province)
select
member_id
,name
,province
from
partition_test_input
where
stat_date='20110728';
stat_date叫做静态分区列,province叫做动态分区列。这样stat_date='20110728’的所有数据,会根据province的不同分别插入到/user/hive/warehouse/partition_test/stat_date=20110728/下面的不同的子文件夹下,如果源数据对应的province子分区不存在,则会自动创建,非常方便,而且避免了人工控制插入数据与分区的映射关系存在的潜在风险。
注:select子句中需要把动态分区列按照分区的顺序写出来,静态分区列不用写出来。
1、尽量不要用动态分区,因为动态分区的时候,将会为每一个分区分配reducer数量,当分区数量多的时候,reducer数量将会增加,对服务器是一种灾难。
2、动态分区和静态分区的区别,静态分区不管有没有数据都将会创建该分区,动态分区是有结果集将创建,否则不创建。
3、hive动态分区的严格模式和hive提供的hive.mapred.mode的严格模式。
hive提供我们一个严格模式:为了阻止用户不小心提交恶意hql
hive.mapred.mode=nostrict : strict
如果该模式值为strict,将会阻止以下三种查询:
(1)对分区表查询,where中过滤字段不是分区字段。
(2)笛卡尔积join查询,join查询语句,不带on条件或者where条件。
(3)对order by查询,有order by的查询不带limit语句。
4、动态分区不允许主分区采用动态列而副分区采用静态列,这样将导致所有的主分区都要创建副分区静态列所定义的分区。
5、动态分区可以允许所有的分区列都是动态分区列,但是要首先设置一个参数:hive.exec.dynamic.partition.mode。
6、注意!!!
hive用了动态分区,若select语句无数据,则insert overwrite并不会覆盖。因为动态分区由select决定,select语句无数据,分区也无法确定,故无法实现动态覆盖。此时想要修正表数据,需要手动删除该分区。
ALTER TABLE pdata_ams.check_deposit_flow_day DROP IF EXISTS PARTITION(busi_date='2022-03-09');