分区表其实就是按照表中数据的某一列的值进行划分文件(自我理解类似于sql查询中的group by),一个分区下包含多个子目录,用于分区的虚拟列有多少种枚举值就有多少个子目录。分区表可以采用一个虚拟列进行分区,也可以采用多个虚拟列进行分区。
分区是在处理大型事实表时常用的方法。分区的好处在于缩小查询扫描范围,从而提高速度。分区分为两种:静态分区static partition和动态分区dynamic partition。静态分区和动态分区的区别在于导入数据时,是手动输入分区名称,还是通过数据来判断数据分区。对于大数据批量导入来说,显然采用动态分区更为简单方便。
create table partition_table1 (id int, name string) partitioned by (age int) row format delimited fields terminated by ‘,’;
上面语句中创建的表partition_table1中的数据文件中的列只有id和name,而没有age,所以说age是虚拟列。
create table partition_table2 (id int, name string) partitioned by (age int, grade int) row format delimited fields terminated by ‘,’ ;
上面语句中创建的表partition_table2所用的分区的虚拟列为两列age,grade,所以在partition_table2目录下,会首先根据age进行分目录,然后每个age目录下会根据grade分目录,即先根据age分区,之后对结果再根据grade分区。
把表中的大多数字段建立为分区字段,可行吗?分区不是越多越好,分区越多的话,加载数据的话必须注意分区,那么文件会被控制的非常小,Map的任务数量增多,
分区多了计算不一定会快。Hive限定了分区的数量。选用一些查询比较频繁的字段来建立分区,时间字段等。
查询比较频繁,并且不会有很多枚举值的字段,适合作为分区字段。分区字段就是虚拟列(virtual column)。
为分区表导入数据时,有两种方式,一种是通过load data读取文件导入表,另一种是通过hive的insert命令从其他表中查询结果导入表
1、通过load data: load data local inpath ‘/user/data/f1.txt’ into table partition_table2 partition(age=18,grade=2);
当数据被加载至表中时,不会对数据进行任何转换。Load操作只是将数据复制至Hive表对应的位置。数据加载时在表下自动创建一个目录
为了让分区列的值相同的数据尽量在同一个mapreduce中,这样每一个mapreduce可以尽量少的产生新的文件夹,可以借助distribute by的功能,将分区列值相同的数据放到一起:
hive> insert overwrite table partition_test partition(stat_date,province)
> select member_id,name,stat_date,province from partition_test_input distribute by stat_date,province;
2、通过insert子句:insert into table partition_table2 partition(age=18,grade=2) select id,name from original_table where age=18 and grade=2;
下面介绍一下动态分区,因为按照上面的方法向分区表中插入数据,如果源数据量很大,那么针对一个分区就要写一个insert,非常麻烦。况且在之前的版本中,必须先手动创建好所有的分区后才能插入,这就更麻烦了,你必须先要知道源数据中都有什么样的数据才能创建分区。
使用动态分区可以很好的解决上述问题。动态分区可以根据查询得到的数据自动匹配到相应的分区中去。
使用动态分区要先设置hive.exec.dynamic.partition参数值为true,默认值为false,即不允许使用:
hive> set hive.exec.dynamic.partition;
hive.exec.dynamic.partition=false
hive> set hive.exec.dynamic.partition=true;
hive> set hive.exec.dynamic.partition;
hive.exec.dynamic.partition=true
动态分区的使用方法很简单,假设我想向stat_date=’20110728’这个分区下面插入数据,至于province插入到哪个子分区下面让数据库自己来判断,那可以这样写:
hive> insert overwrite table partition_test partition(stat_date=’20110728′,province)
> select member_id,name,province from partition_test_input where stat_date=’20110728′;
Total MapReduce jobs = 2
…
3 Rows loaded to partition_test
OK
stat_date叫做静态分区列,province叫做动态分区列。select子句中需要把动态分区列按照分区的顺序写出来,静态分区列不用写出来。这样stat_date=’20110728’的所有数据,会根据province的不同分别插入到/user/hive/warehouse/partition_test/stat_date=20110728/下面的不同的子文件夹下,如果源数据对应的province子分区不存在,则会自动创建,非常方便,而且避免了人工控制插入数据与分区的映射关系存在的潜在风险。
注意,动态分区不允许主分区采用动态列而副分区采用静态列,这样将导致所有的主分区都要创建副分区静态列所定义的分区:
hive> insert overwrite table partition_test partition(stat_date,province=’liaoning’)
> select member_id,name,province from partition_test_input where province=’liaoning’;
FAILED: Error in semantic analysis: Line 1:48 Dynamic partition cannot be the parent of a static partition ‘liaoning’
动态分区可以允许所有的分区列都是动态分区列,但是要首先设置一个参数hive.exec.dynamic.partition.mode :
hive> set hive.exec.dynamic.partition.mode;
hive.exec.dynamic.partition.mode=strict
它的默认值是strick,即不允许分区列全部是动态的,这是为了防止用户有可能原意是只在子分区内进行动态建分区,但是由于疏忽忘记为主分区列指定值了,这将导致一个dml语句在短时间内创建大量的新的分区(对应大量新的文件夹),对系统性能带来影响。
所以我们要设置:
hive> set hive.exec.dynamic.partition.mode=nostrick;
删除分区表:删除分区表时,元数据和数据都会被删除。
ALTER TABLE PARTITION_TABLE1 DROP PARTITION(AGE=
原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/9539.html