hive 建表,分桶表(clustered by)、分桶且桶内排序(clustered by+sorted by)、分区表(partitioned by)、分区分桶一起用

mac2024-07-15  52

一、分桶表

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段数据的排序。。

 

更详细的原来请看:https://www.jianshu.com/p/922e2e37ae22

三、分区表

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;

参考:https://blog.csdn.net/afafawfaf/article/details/80249974

2、原理:

 

不论insert还是load data,其实都是把数据全部放到该表的目录下的与分区名同名的目录下。。

这样的好处就是:

查询的时候把分区当做一个字段使用,在where条件中指定month='2015-01-19',那么hive在查询数据只就只扫描该分区文件夹下面的数据,其他分区的数据就忽略了。可以提升效率。

 

 

四、分区分桶一起用

一起用时,在insert时就要指定分区(或者冬天分区),然后按照分桶规则,在每个分区目录下进行分桶。

 

 

 

 

 

最新回复(0)