一、分桶表
1、建表语句
create table test_bucket_sorted (
id int comment 'ID',
name string comment '名字'
)
comment '测试分桶'
clustered by(id) sorted by (id) into 4 buckets
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' ;
上面建表指定了这张表分为四个桶。
2、原理:hive的分桶就是mapreduce的partition。
(1)原理:当insert插入数据到分桶表时,会把insert的sql转为mapreduce程序处理,而分桶表的桶数就是reducer的数量。
然后使用分桶键作为mapreduce的partition分区键,每条数据的分桶键的hash对桶数求余的值 就是这一条数据所属reducer的索引。
我们知道,每个reducer都会一个文件。所以上面例子中的桶数是四,那么insert插入数据到分桶表后,我们在该表的hdfs目录下可以看到新增了四个文件。。文件命名与reducer的输出文件命名风格一样。
(2)注意:
《1》默认情况下,当插入的数据量不大的时候,是不会分桶的。
然后我测试的数据就只有9条:
[root@hadoopTest ~]# cat data.txt
1 name1
2 name2
3 name3
4 name4
5 name5
6 name6
7 name7
8 name8
9 name9
先把这些数据放到中间表里,这样才能用insert...select
所以为了测试出效果,我们需要设置属性为强制分桶:set hive.enforce.bucketing=true;
这样的话我们的insert就会分为四个reducer处理了。hdfs输出文件如下:
如果再次分桶插入数据,那么又会产生四个新文件:
《2》load data方式插入数据是不会分桶的,因为根本不会转为mapreduce程序处理。。
3、分桶表的作用:
方便数据抽样:select * from teacher tablesample(bucket 1 out 3 on name);
注:分桶语法----TABLESAMPLE(BUCKET x OUT OF y)
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。 例如:table总共分了3份,当y=3时,抽取(3/3)=1个bucket的数据,当y=6时,抽取(3/6)=1/2个bucket的数据。
x表示从哪个bucket开始抽取。
例如:table总bucket数为3,tablesample(bucket 3 out of 3),表示总共抽取(3/3=)1个bucket的数据,抽取第3个bucket的数据。再例如:table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据,分别为第3个bucket和第(3+16=)19个bucket的数据。
查询第一个桶里数据,并返回一半数据:
select * from teacher tablesample(bucket 1 out of 6 on name);
二、分桶且桶内排序(clustered by+sorted by)
sorted by是需要与clustered by一起用的,不能单独用
1、建表
create table test_bucket_sorted (
id int comment 'ID',
name string comment '名字'
)
comment '测试分桶'
clustered by(id) sorted by (id) into 4 buckets
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' ;
2、insert数据
insert数据到该表中所转为的mapreduce程序为:
将会启动与分桶数的相同的reducer任务。 按id进行partition分区,不同数据根据partition分区给不同reducer处理。
然后,同一个reducer处理的数据都会按照sorted by 指定的字段进行排序。
从这里就能够知道,分桶表与分桶排序其实就是在insert数据到该表时,读取到该表设置了分桶与分桶排序,那么就会根据建表的分桶信息设置一个partitioner,然后根据建表的sorted by字段设置reducer阶段的WritableComparator,用于reducer段数据的排序。。
更详细的原来请看:Hive分桶表学习总结 - 简书
三、分区表
1、建表语句:
create table dept_partition(deptno int, dname string, loc string)
partitioned by (month string)
row format delimited fields terminated by '\t';
2、插入和导入语句
(1)静态分区
insert overwrite table dept_partition partition(month='2015-01-19') select * from test;
load data local inpath '/root/hive/partitions/file1' into table dept_partition
partition (month='2015-01-19');
都是在后面指定要插入或者导入的分区就行。。。"2015-01-19"这个分区是一个文件夹,而文件夹的名字就是2015-01-19。
(2)动态分区
在insert ...select时,使用select 查询出的字段列表中的最后的字段作为分区的key(如果分区字段只有一个,那么就是使用select列表中的最后一个字段,如果分区字段有多个,那么就使用select列表的最后n个字段作为分区key),该字段值相同的数据会放到同一个分区。
#启动动态分区功能
set hive.exec.dynamic.partition=true;
#允许全部分区都是动态分区
set hive.exec.dynamic.partition.mode=nostrick;
#month_id为静态分区,day_id为动态分区:
insert overwrite table dynamic_test partition(month_id='201710',day_id)
select c1,c2,c3,c4,c5,c6,c7,day_id from kafka_offset
where substr(day_id,1,6)='201710';
# month_id和 day_id均为动态分区:
insert overwrite table dynamic_test partition(month_id,day_id)
select c1,c2,c3,c4,c5,c6,c7,substr(day_id,1,6) as month_id,day_id from kafka_offset;
为了让分区列的值相同的数据尽量在同一个mapreduce中,这样每一个mapreduce可以尽量少的产生新的文件夹,可以借助distribute by的功能,将分区列值相同的数据放到一起。
insert overwrite table dynamic_test partition(month_id,day_id)
select c1,c2,c3,c4,c5,c6,c7,substr(day_id,1,6) as month_id,day_id from kafka_offset
distribute by month_id,day_id;
参考:Hive分区表的分区操作_IT影风的博客-CSDN博客
2、原理:
不论insert还是load data,其实都是把数据全部放到该表的目录下的与分区名同名的目录下。。
这样的好处就是:
查询的时候把分区当做一个字段使用,在where条件中指定month='2015-01-19',那么hive在查询数据只就只扫描该分区文件夹下面的数据,其他分区的数据就忽略了。可以提升效率。
四、分区分桶一起用
一起用时,在insert时就要指定分区(或者冬天分区),然后按照分桶规则,在每个分区目录下进行分桶。