1. 前言
分桶是相对分区进行更细粒度的划分。在分区数量过于庞大以至于可能导致文件系统崩溃时,我们就需要使用分桶来解决问题。
分桶将整个数据内容按照某列属性值的Hash值进行划分。比如,如果按照ID属性分为4个桶,就是对ID属性值的Hash值对4取模,按照取模的结果对数据进行分桶。举个例子:
例如对属性的Hash值按4取模,取模结果为0的数据记录存放到一个文件中,取模为1的数据存放到一个文件中,取模为2的数据存放到一个文件中,取模为3的数据存放到一个文件中。
2. 表的分桶
2.1 建立带有分桶的表
分桶同样应当建表时就建立,建表语句与之前建立分区表类似。下面还是以person表为例,其建表语句如下:
create table person(
id int,
name string,
age int,
fav array<string>,
addr map<string, string>
)
comment 'This is the person table'
partitioned by (dt string)
clustered by (id) into 3 buckets
row format delimited fields terminated by '\t'
collection items terminated by '-'
map keys terminated by ':'
stored as textfile;
其中:
clustered by (id) into 3 buckets
用来进行分桶操作,以字段id为分桶依据,将每个分区分成3个桶。
2.2 导入数据
导入数据的语句与分区表时没有任何区别,还是向分区中导入数据:
load data local inpath '/home/hadoop/input/person.txt' overwrite into table person partition (dt='20190920');
2.3 查询
如果要查询3个桶中第1个桶的全部数据,可以通过以下查询语句进行查询:
select * from person tablesample(bucket 1 out of 3 on id);
为什么第一个桶的数据是id为3的数据?因为对3取模后得到的是0,所以被分配到第一个桶内。下面让我们验证以下,查看第二个桶内的数据:
select * from person tablesample(bucket 2 out of 3 on id);
得到结果如下:
可以看到查询得到的是id为1的数据,而1对3取模刚好为1,被分配到第二个桶内,同理看一下第三个桶内的数据:
select * from person tablesample(bucket 3 out of 3 on id);
查询结果如下:
3. 来点有趣的分析
前面我们说到:
Hive的表逻辑上由存储的数据和描述表格中的数据形式的相关元数据组成。元数据存储在关系数据库中。表存储的数据存放在Hive的数据仓库中,这个数据仓库是HDFS上的一个目录,该目录在hive-site.xml文件中由${Hive.metastore.warehouse.dir}指定:/user/hive/warehouse/。创建一张Hive的表,即在HDFS的仓库目录下创建一个文件夹。
而表分为内部表和外部表两种,那么我们之前创建的这个表是属于内部表还是外部表呢?关于内部表和外部表我将在一下篇进行详细的分析,这里先看一下/user/hive/warehouse文件吧,留个念想: