1分桶
1.1什么是分桶?和分区有什么区别?
分区:Hive在查询数据的时候,一般会扫描整个表的数据,会消耗很多不必要的时间。有些时候,我们只需要关心一部分数据,比如WHERE子句的查询条件,那这时候这种全表扫描的方式是很影响性能的。从而引入了分区的概念。分区就是对数据进行分类,这样在查询的时候,就可以只是针对分区查询,从而不必全表扫描。
一个目录对应一个分区
分桶:并非所有的数据集都可形成合理的分区,特别之前所提到过的要确定合适的划分大小的疑虑。对于每一个表或者分区,可以进一步细分成桶,桶是对数据进行更细粒度的划分。Hive默认采用对某一列的每个数据进行hash(哈希),使用hashcode对 桶的个数求余,确定该条记录放入哪个桶中。
分桶实际上和 MapReduce中的分区是一样的。分桶数和reduce数对应。
一个文件对应一个分桶
1.2如何创建一个分桶?
1.2.1 语法格式
CREATE [EXTERNAL] TABLE <table_name>
(<col_name> <data_type> [, <col_name> <data_type> ...])]
[PARTITIONED BY ...]
CLUSTERED BY (<col_name>)
[SORTED BY (<col_name> [ASC|DESC] [, <col_name> [ASC|DESC]...])]
INTO <num_buckets> BUCKETS
CLUSTERED BY (<col_name>):以哪一列进行分桶
SORTED BY (<col_name> [ASC|DESC]:对分桶内的数据进行排序
INTO <num_buckets> BUCKETS:分成几个桶
具体解释:
只能对一列进行分桶。表可以同时分区和分桶,当表分区时,每个分区下都会有<num_buckets> 个桶。当使用 SORTED BY … 在桶内排序时,指定排序的列和指定分桶的列无需相同。ASC 为升序选项,DESC 为降序选项,默认排序方式是升序。<num_buckets> 指定分桶个数,也就是表目录下小文件的个数。
1.2.2 创建分桶实例
(1)创建一个student表:
hive> create table student(
st_id int,
st_name string,
st_sex string,
st_age int,
st_dept string
)
clustered by(st_dept) sorted by(st_age desc) into 3 buckets
row format delimited fields terminated by ',';
// sorted by可以省略
(2)查看表结构:
hive> desc formatted student;
Num Buckets: 3
导入数据有两种,一种是通过文件导入,但是并不会真正的分桶 ;一种是通过从其他表插入的方式导入数据,这种方式才能真正的分桶;
(3)建一个普通的student1表
hive> create table student1(st_id int,st_name string,st_sex string,st_age int,
> st_dept string) row format delimited fields terminated by ',';
(4)导入数据到student1表
hive> load data local inpath '/hive/student.txt' into table student1;
(5)导入数据到分桶的表
方法一:
<pre>//打开强制分桶开关:</pre>
hive (myhive)> set hive.enforce.bucketing=true;
//设置reduces数为-1:
hive (myhive)> set mapreduce.job.reduces=-1;
//通过其他表插入数据
hive (myhive)> insert into table student select id, name from stu ;
(通过这种方法,得到的分桶对应的文件,数据是无序的,也就是 sorted by 或 sort by无效)
如果没有设置 bucketing属性,我们需要自己设置和分桶个数相匹配的reducer个数。
方法二:
//关闭强制分桶开关:
hive (myhive)> set hive.enforce.bucketing=false;
//设置reduces数和分桶数一致:
hive (myhive)> set mapreduce.job.reduces=3;
//通过其他表插入数据,要添加 distribute by 以及 sort by。
hive (myhive)> insert into table student select id, name from stu distribute by st_dept;
注意:hive.enforce.bucketing为true时,reduce要设为-1;
hive.enforce.bucketing为false时,reduce要设为和分桶数一致;
如果bucketing为 true,reduce又设成大于1的输,会执行两个job。
(为什么通过 load data 的方式导入数据到 student表,并不会分桶?
load data只是把文件上传到 表所在的HDFS目录下。并没有做其他操作。)
总结:我们发现其实桶的概念就是MapReduce的分区的概念,两者完全相同。物理上每个桶就是目录里的一个文件,一个作业产生的桶(输出文件)数量和reduce任务个数相同。
而分区表的概念,则是新的概念。分区代表了数据的仓库,也就是文件夹目录。每个文件夹下面可以放不同的数据文件。通过文件夹可以查询里面存放的文件。但文件夹本身和数据的内容毫无关系。
桶则是按照数据内容的某个值进行分桶,把一个大文件散列称为一个个小文件。这些小文件可以单独排序。如果另外一个表也按照同样的规则分成了一个个小文件。
分桶的好处:
1、两个表join的时候,就不必要扫描整个表,只需要匹配相同分桶的数据即可。效率当然大大提升。
2、同样,对数据抽样的时候,也不需要扫描整个文件。只需要对每个分区按照相同规则抽取一部分数据即可。
2 分桶抽样查询
对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。Hive可以通过对表进行抽样来满足这个需求。
查询表stu_buck中的数据。
hive (myhive)> select * from student tablesample(bucket 1 out of 3 on id);
注:tablesample是抽样语句,语法:TABLESAMPLE(BUCKET x OUT OF y) 。
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了4份,当y=2时,抽取(4/2=)2个bucket的数据,当y=8时,抽取(4/8=)1/2个bucket的数据。
x表示从哪个bucket开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上y。例如,table总bucket数为4,tablesample(bucket 1 out of 2),表示总共抽取(4/2=)2个bucket的数据,抽取第1(x)个和第3(x+y)个bucket的数据。
注意:x的值必须小于等于y的值,否则
FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause for table stu_buck
数据块抽样
Hive提供了另外一种按照百分比进行抽样的方式,这种是基于行数的,按照输入路径下的数据块百分比进行的抽样。
hive (myhive)> select * from student tablesample(0.1 percent) ;
提示:这种抽样方式不一定适用于所有的文件格式。另外,这种抽样的最小抽样单元是一个HDFS数据块。因此,如果表的数据大小小于普通的块大小128M的话,那么将会返回所有行。
喜欢的朋友可以关注下公众号:圳鹏科技