Hive 桶
对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
把表(或者分区)组织成桶(Bucket)有两个理由:
(1)获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。
(2)使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。
测试:一个4000万和一个5000多万的表Join,关联键数据倾斜,并且笛卡尔积,效果明显。
建立小表
create table lxw_test1(id int,name string,date_time string)
clustered by(id) sorted by(id) into 10 buckets;
建立大表
create table lxw_test2(id int,name string,date_time string)
clustered by(id) sorted by(id) into 5 buckets;
ps:
1.两个表关联键为id,需要按id分桶并且做排序,小表的分桶数是大表分桶数的倍数。
2.对于map端连接的情况,两个表以相同方式划分桶。处理左边表内某个桶的 mapper知道右边表内相匹配的行在对应的桶内。因此,mapper只需要获取那个桶 (这只是右边表内存储数据的一小部分)即可进行连接。这一优化方法并不一定要求 两个表必须桶的个数相同,两个表的桶个数是倍数关系也可以
3.桶中的数据可以根据一个或多个列另外进行排序。由于这样对每个桶的连接变成了高效的归并排序(merge-sort), 因此可以进一步提升map端连接的效率
启用桶表
set hive.enforce.bucketing = true;
往小表中插入4000万条记录
insert overwrite table lxw_test1
select id,name,null
from woa_all_user_info_his
where pt = '2012-05-28'
limit 40000000;
往大表中插5000多万条记录(woa_all_user_info_his中有5000多万条记录)
insert overwrite table lxw_test2
select id,name,date_time
from woa_all_user_info_his
where pt = '2012-05-28';
设置Sort Merge Bucket Map Join的参数
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
ps:此时的状况是Bucket columns==Join Columns==Sort Columns,完全具备具备使用Sort Merge Bucket Map Join的条件。
查询
select /*+ mapjoin(b) */ count(1)
from lxw_test1 a
join lxw_test2 b
on a.id = b.id
测试结果:
包括insert数据,采用Sort Merge Bucket Map Join的方式耗时10分钟左右。
如果这两个表做普通的join,耗时1个多小时,还跑不完,最后只得Kill掉了!