Hive分桶超详细!!!
1、分桶的意义
数据分区可能导致有些分区,数据过多,有些分区,数据极少。分桶是将数据集分解为若干部分(数据文件)的另一种技术。
分区和分桶其实都是对数据更细粒度的管理。当单个分区或者表中的数据越来越大,分区不能细粒度的划分数据时,我们就采用分桶技术将数据更细粒度的划分和管理。
分桶其实跟我们MR中的分区是一样的。
2、分桶的原理
与MapReduce中的HashPartitioner的原理一模一样
MapReduce:使用key的hash值对reduce的数量进行取模(取余)
hive:使用分桶字段的hash值对分桶的数量进行取模(取余)。针对某一列进行分桶存储。每一条记录都是通过分桶字段的值的hash对分桶个数取余,然后确定放入哪个桶。
MapReduce: Key 单词 reduce的数量是3个,最后形成3个。
hello --> hello 进行hash算法 --> 得到的hash值对3取模(0 1 2)
MapReduce假如不指定分区,是否有分区呢?答案是有,使用默认分区HashPartitioner。
Hive --> 假如 我指定分桶字段为 id , 桶的数量为 3个,就是hash(id) % 3 = 0 1 2
桶是一个个的文件,分区是一个个的文件夹。
hash 是一种算法,你需要知道,任何值都可以 hash
举例:hello --> 237847238
"hello".hashCode()
3、分桶有啥好处
分区的意义:提高查询效率
分桶的意义:将每一个分区的数据进行切分,变成一个个小文件,然后进行抽样查询(从一堆数据中找一些数据进行分析)。在进行多表联查的时候,可以提高效率(hive优化的时候再提)。
两个大表 join,使用分桶表,查询速度快。
4、分桶的实战
创建分桶的表:
create table stu_bucket(id int, name string)
clustered by(id)
into 4 buckets
row format delimited fields terminated by ' ';
设置reduce的数量:
注意:
想要将表创建为4个桶,需要将hive中mapreduce.job.reduces参数设置为>=4或设置为-1;
通过 set mapreduce.job.reduces ; 可以查看参数的值
hive (yhdb)> set mapreduce.job.reduces;
mapreduce.job.reduces=-1
hive (yhdb)> set mapreduce.job.reduces=-1;
reduces = -1 表示让系统自行决定reduce的数量。
在 wordcount 的时候,创建了三个分区,reduce 的数量设置为 3,最合理,也可以设置为 1,也可以设置为 4。
加载数据:
建议:不要使用load直接加载!
使用:创建普通表,加载普通表的数据到分桶表。
数据:student.txt
1001 ss1
1002 ss2
1003 ss3
1004 ss4
1005 ss5
1006 ss6
1007 ss7
1008 ss8
1009 ss9
1010 ss10
1011 ss11
1012 ss12
1013 ss13
1014 ss14
1015 ss15
1016 ss16
建议不要使用load直接加载,但是可以尝试一下:
load data local inpath '/home/hivedata/student.txt' into table stu_bucket;
如上所示:Hive的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
1、reduce=-1 让job自行决定开启多少个reduce,或者设置数量大于等于桶的数量。
2、建议关闭本地模式:
官方建议使用 创建临时表加载数据:使用insert将数据插入到分桶表
hive(yhdb)> truncate table stu_bucket;(删除表内数据,不删表结构,因此只能删内表)
hive(yhdb)> create table temp_stu(id int, name string)
row format delimited fields terminated by ' ';
hive(yhdb)> load data local inpath '/home/hivedata/student.txt' into table temp_stu;
hive(yhdb)> insert into table stu_bucket select * from temp_stu cluster by (id);
5、分桶的查询
数据不对
语法: tablesample(bucket x out of y on sno)
select * from stu_bucket;
select * from stu_bucket tablesample(bucket 1 out of 1);
查询第一桶
select * from stu_bucket tablesample(bucket 1 out of 4 on id);
查询第一桶和第三桶
select * from stu_bucket tablesample(bucket 1 out of 2 on id);
查询第二桶和第四桶的数据
select * from stu_bucket tablesample(bucket 2 out of 2 on id);
查询对8取余的第一桶的数据:
select * from stu_bucket tablesample(bucket 1 out of 8 on id);
其他查询:
查询前三条
select * from stu_bucket limit 3;
select * from stu_bucket tablesample(3 rows);
查询百分比的数据
select * from stu_bucket tablesample(13 percent);大小的百分比所占的那一行。
查询固定大小的数据
select * from stu_bucket tablesample(68b); 单位(K,KB,MB,GB...)
固定大小所占的那一行。 byte--字节 bit --位
随机抽三行数据
select * from stu_bucket order by rand() limit 3;
6、总结(重要)
定义阶段:
clustered by (id); ---指定表内的字段进行分桶。
sorted by (id asc|desc) ---指定数据的排序规则,表示咱们预期的数据是以这种规则进行的排序
举例:
create table stu_bucket2(id int, name string)
clustered by(id) sorted by(id desc)
into 4 buckets
row format delimited fields terminated by ' ';
sorted by 指定分桶表中的每一个桶的排序规则
导入数据阶段:
cluster by (id)
--指定getPartition以哪个字段来进行hash,并且排序字段也是指定的字段,排序是以asc排列
--相当于distribute by (id) sort by (id)
insert into table stu_bucket select * from student cluster by (id);
想当于:
insert into table stu_bucket select * from student distribute by (id) sort by (id) ;
distribute by (id) -- 指定getPartition以哪个字段来进行hash
sort by (name asc | desc) --指定排序字段
-- 区别:distribute by 这种方式可以分别指定getPartition和sort的字段
总结:
分区使用的是表外字段,分桶使用的是表内字段
分桶更加细粒度的管理数据,更多的是使用来做抽样、join
cluster 和 clusted 的区别:一个是导入数据的时候调用的,一个是创建表的时候使用的。
sort by 和 sorted by 区别:sort by 是导入数据的时候,sorted by 是分桶排序规则指定的时候
distribute by 和 cluster by 的区别:前一个是分区,后一个是分区并排序。
partition by 和 partitioned by 的区别:partition by 一般和开窗函数一起使用,partitioned by 建表的时候一起使用。