一文彻底学会hive分桶表(实战详解)

一、分桶表概述

1.1、什么是分桶表?

分桶是将数据集分解成更容易管理的若干部分的一个技术,是比表或分区更为细粒度的数据范围划分。针对某一列进行桶的组织,对列值哈希,然后除以桶的个数求余,决定将该条记录存放到哪个桶中。

常用于:

  • 获得更高的查询处理效率
  • 抽样调查
1.2、分桶表和分区表有啥区别?

分区表提供了一个隔离数据和优化查询的便利方式。但是在实际场景下,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive还可以进一步组织成桶,也就是更为细粒度的数据范围划分。

小结一波:

  1. 分桶对数据的处理比分区更加细粒度化;
  2. 分桶和分区两者不干扰,可以把分区表进一步分桶;
  3. 分区针对的是数据的存储路径;分桶针对的是数据文件。

二、分桶表实战

首先说明一下,我的hive环境是基于docker-compose构建,使用postgresql管理metastore,各重要组件版本如下:

hadoop:2.7.4

hive:2.3.2

java:1.8

其实环境不重要,不用花太多时间,主要还是技术部分,接下来就开始实战吧。

2.1、创建一个分桶表

我们创建一个简单的分桶表,只有两个字段(id,name),并且按照id进行分6个桶,sql如下:

create table test_buck(id int, name string)
clustered by(id) 
into 6 buckets
row format delimited fields terminated by '\t';

执行并查看表结构:
创建分桶表并查看表结构

使用desc formatted test_buck;查看test_buck表结构,数据较多,这里截取重要数据如下:
分桶表结构重要数据

2.2、准备数据

准备一些编号和字符串并按照 "\t"分隔开,把这些数据放入/tools/目录下的test_buck.txt文件内,数据格式如下图:
数据样式

2.3、向分桶表导入数据
2.3.1、错误导入示范(引出分桶的本质)

数据准备好之后,我们就可以向分桶表里导入数据里。这里我首先使用如下常规命令导入:

load data local inpath '/tools/test_buck.txt' into table test_buck;

然后很惊奇的是它报错了,报错信息如下:
报错信息

简单翻译一下,报错信息是这样说的:请把数据导入到一个中间表,并使用insert … select语句导入到分桶表里。如果你非要直接导入分桶表里,需要把hive.strict.checks.bucketing设置为false(关闭严格模式),然后你写sql就没有检查了。。。。。

哈哈,到这里,我们知道了分桶表应该怎么导入数据了,但是为啥直接导入就不行呢?下面让我们硬着头皮改为false,然后导入数据试一下。

set hive.strict.checks.bucketing = false;

取消严格模式并插入数据
然后我们打开50070查看hdfs上数据如下:

查看结果数据
说好的分6个桶呢?为什么只有一个呢?

这是因为:

桶的概念就是MapReduce的分区的概念,两者是完全一样的。也就是说物理上每个桶就是目录里的一个文件,一个作业产生的桶(输出文件)数量和reduce任务个数相同

所以这里我们导入一个文件,由于分区数等于文件数,只有一个分区,所以上面的操作并没有分桶。

2.3.2、正确导入示范(引出分桶规则)

绕了一圈,感觉还是把hive.strict.checks.bucketing设置为true比较好,节省犯错成本(不过有时候多犯错也是好事,比如上面咱们至少知道了hive分桶本质上就是mapreduce的分区)。

把hive严格模式打开,并把桶表清空:

set hive.strict.checks.bucketing = true;
truncate table test_buck;

下面我们使用之前严格模式下建议我们使用的分桶表导入数据方式,使用中间表来进行数据导入:

  1. 设置强制分桶为true,并设置reduce数量为分桶的数量个数。

    set hive.enforce.bucketing = true;
    

    启用强制分桶

  2. 创建一个临时表,并导入数据。

    create table temp_buck(id int, name string)
    row format delimited fields terminated by '\t';
    load data local inpath '/tools/test_buck.txt' into table temp_buck;
    

    创建临时表并导入数据

  3. 使用insert select来间接把数据导入到分桶表。

    insert into table test_buck select id, name from temp_buck;
    
  4. 在50070上查看分桶表的数据,已经分为了6个,桶表数据插入成功!
    分桶数据

  5. 查询分桶表里的数据。

    select * from test_buck;
    

    结果如下图,仔细观察:
    查询分桶表的数据

通过观察规则和桶数的对应关系,我们可以得出如下分桶规则

  • Hive的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中
2.4、分桶抽样

对表分桶一般有两个目的,提高数据查询效率、抽样调查。通过前面的实战,我们已经可以对分桶表进行正常的创建并导入数据了。一般在实际生产中,对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。这个时候Hive就可以通过对表进行抽样来满足这个需求。

抽样语句语法解析:

tablesample(bucket x out of y)
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。
例如,table总共分了6份,当y=2时,抽取(6/2=)3个bucket的数据,当y=8时,抽取(6/8=)3/4个bucket的数据。
x表示从哪个bucket开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上y。
例如,table总bucket数为6,tablesample(bucket 1 out of 2),表示总共抽取(6/2=)3个bucket的数据,抽取第1(x)个和第3(x+y)个和第5(x+y)个bucket的数据。
注意:x的值必须小于等于y的值

举例:

select * from test_buck tablesample(bucket 1 out of 3 on id);

结果如下图,可以发现,上面这条sql查出了第1个和第4个桶的数据:
抽样结果数据

三、总结

3.1、分桶表的优点
  1. 查询效率更快,因为分桶为表加上了额外结构,链接相同列划分了桶的表,可以使用map-side join更加高效;
  2. 由于分桶规则保证了数据在不同桶的随机性,因此平时进行抽样调查时取样更加方便。
3.2、常用操作
  1. 建表语句及含义

    create table buck_table_name (id int,name string)
    clustered by (id) sorted by (id asc) into 4 buckets
    row format delimited fields terminated by '\t';
    注意:CLUSTERED BY来指定划分桶所用列和划分桶的个数。
    分桶规则:HIVE对key的hash值除bucket个数取余数,保证数据均匀随机分布在所有bucket里。
    SORTED BY对桶中的一个或多个列另外排序
    
  2. 导入数据

    先把数据导入中间表,然后使用insert select语句进行间接导入到分桶表,比如咱们实战的例子:

    insert into table test_buck select id, name from temp_buck;
    
3.3、分桶表的实质及与分区表的区别

hive的桶其实就是MapReduce的分区的概念,两者完全相同。在物理上每个桶就是目录里的一个文件,一个作业产生的桶(输出文件)数量和reduce任务个数相同。

分区代表了数据的仓库,也就是文件夹目录。每个文件夹下面可以放不同的数据文件。通过文件夹可以查询里面存放的文件。但文件夹本身和数据的内容毫无关系。

桶则是按照数据内容的某个值进行分桶,把一个大文件散列称为一个个小文件。这些小文件可以单独排序。如果另外一个表也按照同样的规则分成了一个个小文件。两个表join的时候,就不必要扫描整个表,只需要匹配相同分桶的数据即可,效率当然大大提升。

同样的道理,在对数据抽样的时候,也不需要扫描整个文件。只需要对每个分区按照相同规则抽取一部分数据即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章