以下内容参考自《Hive编程指南》
1、简单理解
简单理解,分区就是不同的目录结构,表是最外层的目录,表里面的分区对应表目录里的各个子目录,例如:
...
.../employees/country=CA/state=AB
.../employees/country=CA/state=BC
...
.../employees/country=US/state=AL
.../employees/country=US/state=AK
...
在一般情况下,对于分区表不需要去考虑其分区字段,可以将其视为不同的字段进行使用,在《Hive编程指南》中说道,除非需要优化查询性能,否则使用这些表(分区表)的用户不需要关心这些“字段”是否是分区字段。
也正是由于分区是不同目录的设计,在表数据很大的情况下,查询时使用分区表的分区字段,可以省略掉那些不满足条件的目录,仅仅关注于符合条件的目录。这样,对于非常大的数据集,分区可以显著地提高性能。
2、分区的设计
通过以上的分析,已经对分区表有了简单的理解,但是需要考虑到的是,Hive表中的数据本身是存储在HDFS中的。HDFS是用于存储数百万的大文件,而非数十亿的小文件,使用过多的分区就对应着一个包含多个文件的文件夹。而文件是由NameNode管理的,并且NameNode必须将所有的系统文件的元数据信息保存在内存中。当分区数量足够大时,会导致NameNode的响应速度。
MapReduce会将一个任务(job)转换成多个任务(task)。默认情况下,每个task都是一个新的JVM实例,都需要开启和销毁的开销。对于小文件,每个文件都对应一个task。在某些情况下,JVM开启和销毁的时间中销毁可能会比实际处理数据的时间消耗更长。
因此,一个理想的分区方案不应该导致产生太多的分区和文件夹目录,并且每个目录下的文件应足够大,最理想的情况是文件系统块大小(128M)的若干倍。
另外,若找不到好的、大小相对合适的分区方式的话,可以考虑使用“分桶表数据存储”。
3、通过查询语句向表中插入数据
静态分区插入
通过下面的语句可以向指定表的指定分区中插入select后的数据:
insert into/overwrtie table table_name partition (column='',...)
select * from table_name where ...;
动态分区插入
对于分区数量很多或者分区是根据表中某一列值(可以对其进行一些计算)的分区中插入数据时,就需要动··态分区功能,其可以基于查询参数推断出需要创建的分区名称:
insert into/overwrite table table_name partition (column1,column2)
select ..., column1, column2 from table_name where ...;
需要注意的是,Hive根据select语句中的最后两列来确定分区字段column1与column2的,源表字段值和输出分区值之间的关系是根据位置而不是根据命名来匹配的。
混用动态和静态分区
用法参考以上,需要注意的是,静态分区键必须出现在动态分区键之前。
动态分区的属性设置
属性名称 | 缺省值 | 描述 |
---|---|---|
hive.exec.dynamic.partition | false | 设置成true,表示开启动态分区功能 |
hive.exec.dynamic.pratition.mode | strict | 设置成nonstrict,表示允许所有分区都是动态的 |
hive.exec.max.dynamic.partitions.pernode | 100 | 每个mapper或reducer可以创建的最大动态分区个数。如果某个mapper或reducer尝试创建大于这个值的分区的话会抛出一个错误信息 |
hive.exec.max.dynamic.partitions | +1000 | 一个动态分区创建语句可以创建的最大动态分区个数。如果超过这个值会抛出错误信息 |
hive.exec.max.created.files | 100000 | 全局可以创建的最大文件个数。有一个Hadoop计数器会跟踪记录创建了多少个文件,如果超过这个值会抛出一个错误信息 |