本文主要介绍了Hive中分桶表的使用及作用
分区提供了一个隔离数据和优化查询的便利的方式.但是当分区的数量过多时,会产生过多的小分区,这样会给namenode带来较大的压力.分桶试讲数据集分解成更容易管理的若干部分的另一个技术.
我们先准备我们将使用的分桶表的数据.
1,jack,2016/11/11 2,michael,2016/11/12 3,summer,2016/11/13 4,spring,2016/11/14 5,nero,2016/11/15 6,book,2016/12/21 7,node,2016/12/22 8,tony,2016/12/23 9,green,2016/12/24 10,andy,2016/12/25 11,kaith,2016/12/26 12,spring,2016/12/27 13,andy,2016/12/28 14,tony,2016/12/29 15,green,2016/12/30 16,andy,2016/12/31 17,kaith,2017/1/1 18,xiaoming,2017/1/2如上所示,这是一张顾客信息表,3个字段分别代表顾客的id,name,birthday
桶表的建表语法和普通表类似,但是需要制定分桶的规则和桶的个数.
create table t_bucket(id int,name string,birthday string) clustered by (id) into 4 buckets row format delimited fields terminated by ',';我们设定桶表按照id进行分桶,桶内数据按照id进行排序.注意这里的建表语句只是告诉hive,t_bucket这张表是应该按照这种方式去存储,但是并不会在插入数据时帮我们去分桶存储.我们来做个试验: 我们将上面准备好的数据插入t_bucket表
load data local inpath '/home/spark/jar/testdata/Customer.txt' into table t_bucket;然后我们到hdfs的目录去查看,发现并没有安装我们预先设计的方式去存储数据,数据文件个数为一个;
hive (test_neil)> dfs -ls /user/hive/warehouse/test_neil.db/t_bucket; Found 1 items -rwxr-xr-x 1 root staff 364 2017-02-05 12:44 /user/hive/warehouse/test_neil.db/t_bucket/Customer.txt事实上hive采用的为读时模式,他并不会去判断插入表的数据是否符合元数据的信息.因为我们使用load插入数据并不会产生reduce,数据量较小,只生成了一个数据文件,因此这并不是一个分桶表.一般我们并不采用load的方式去加载数据到bucket表,我们采用insert的方式,使用select将数据变成我们分桶指定的模式.
首先我们把数据导入另外一张表中
create table t_temp(id int,name string,birthday string) row format delimited fields terminated by ','; load data local inpath 'home/spark/jar/testdata/Customer.txt' into table t_temp;在我们导入数据前,需要将hive.enforce.bucketing的值设置为true,
set hive.enforce.bucketing = true这个参数将强制控制ruduce的个数去和我们指定的分桶个数相适配.
将t_bucket表truncate掉,再次导入数据
truncate table t_bucket; insert into table t_bucket select id,name,birthday from t_temp cluster by id;在job执行的log中,我们可以看到最终分桶的情况:
Loading data to table test_neil.t_bucket Table test_neil.t_bucket stats: [numFiles=4, numRows=18, totalSize=346, rawDataSize=328]我们再次去查看t_bucket表的目录发现,这张表的数据已经被分成了四份,这样我们便成功的将文件进行了分桶的操作;
hive (test_neil)> dfs -ls /user/hive/warehouse/test_neil.db/t_bucket; Found 4 items -rwxr-xr-x 1 root staff 78 2017-02-05 13:14 /user/hive/warehouse/test_neil.db/t_bucket/000000_0 -rwxr-xr-x 1 root staff 92 2017-02-05 13:14 /user/hive/warehouse/test_neil.db/t_bucket/000001_0 -rwxr-xr-x 1 root staff 98 2017-02-05 13:14 /user/hive/warehouse/test_neil.db/t_bucket/000002_0 -rwxr-xr-x 1 root staff 78 2017-02-05 13:14 /user/hive/warehouse/test_neil.db/t_bucket/000003_0我们去查看文件的内容:
dfs -cat /user/hive/warehouse/test_neil.db/t_bucket/000000_0; dfs -cat /user/hive/warehouse/test_neil.db/t_bucket/000001_0; dfs -cat /user/hive/warehouse/test_neil.db/t_bucket/000002_0; dfs -cat /user/hive/warehouse/test_neil.db/t_bucket/000003_0;结果:
4/spring/2016/11/14 8/tony/2016/12/23 12/spring/2016/12/27 16/andy/2016/12/31 1/jack/2016/11/11 5/nero/2016/11/15 9/green/2016/12/24 13/andy/2016/12/28 17/kaith/2017/1/1 2/michael/2016/11/12 6/book/2016/12/21 10/andy/2016/12/25 14/tony/2016/12/29 18/xiaoming/2017/1/2 3/summer/2016/11/13 7/node/2016/12/22 11/kaith/2016/12/26 15/green/2016/12/30我们可以看到,我们的客户数据被分成了四份.那么这四份是如何进行划分的呢?其实我们已经制定了按照id进行划分,因此hive使用hash散列的方式,将id个数对桶个数求余数,我们id为18个,对桶个数(4个)求余数,结果为4.这样每个桶最少有4条数据,同时这样的方式得到的桶内数据其实相当于是随机的.
在上面的select语句中,我们使用了cluster by语句执行分桶的方式.我们发现其实桶内的数据是按照id字段进行升序排列的.其实cluster by相当于distribute by+sort by.sort by默认按照升序进行排列.
sort by排序的为reducer内的数据,在这里就是bucket内的数据.这样数据是局部有序的,而order by是全局有序的.执行了order by,最后只能有个reduce,因为要做全局的排序.
但是呢,distribute by+sort by的组合会更加的灵活,因为我们可以去按照id分桶,按照birthday去进行排序.我们可以做如下的试验.
insert into table t_bucket select id,name,birthday from t_temp distribute by id sort by birthday desc;我们再去执行select,发现数据是按照id进行分桶的,但是数据的排列顺序其实是按照birthday进行降序排列的.
16 andy 2016/12/31 12 spring 2016/12/27 8 tony 2016/12/23 4 spring 2016/11/14 17 kaith 2017/1/1 13 andy 2016/12/28 9 green 2016/12/24 5 nero 2016/11/15 1 jack 2016/11/11 18 xiaoming 2017/1/2 14 tony 2016/12/29 10 andy 2016/12/25 6 book 2016/12/21 2 michael 2016/11/12 15 green 2016/12/30 11 kaith 2016/12/26 7 node 2016/12/22 3 summer 2016/11/131.分桶加快了join查询的速度. 对于map端连接的情况,两个表以相同方式划分桶。处理左边表内某个桶的 mapper知道右边表内相匹配的行在对应的桶内。因此,mapper只需要获取那个桶 (这只是右边表内存储数据的一小部分)即可进行连接。这一优化方法并不一定要求 两个表必须桶的个数相同,两个表的桶个数是倍数关系也可以.这样便采用了Map-side join的方式,避免全表进行笛卡尔积的操作.
**关于桶内排序的意义: 桶中的数据可以根据一个或多个列另外进行排序。由于这样对每个桶的连接变成了高效的归并排序(merge-sort), 因此可以进一步提升map端连接的效率。**
**分桶个数: 如果两个表的分桶个数之间没有什么倍数的关系,这样分桶表在做join时并不会提升效率,因为数据随机分发,桶和桶之间并没有对应关系.**
2.使取样(sampling)更加的高效 在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便. 使用上面的t-bucket我们进行演示. 假如我们使用的为一个大规模的数据集,我们只想去抽取部分数据进行查看.使用bucket表可以变得更加的高效
select * from t_bucket tablesample(bucket 1 out of 4); select * from t_bucket tablesample(bucket 1 out of 4 on id);这样表示我们从bucket1开始取样1个bucket的数据.
select * from t_bucket tablesample(bucket x out of y on xx);x表示从哪个bucket进行抽样,桶计数从1开始.y用来计算抽取数据的量,计算方式为分桶数/y.假设我们一共分了128个桶,y设置为32,则表示要抽取4个bucket,如果x为12,则抽取的数据来自于12/13/14/15.y的值可以不为桶个数的公约数,可以为任意值.
Hive 基础之:分区、桶、Sort Merge Bucket Join
