hive 三种join实现

2022-04-18 11:08:23 浏览数 (2)

众所周知,hive 提供了三种join方式,common join/map join/ smb join,那么如何选择最合适的join 类型?

1. common join是最常见的join 类型,需要执行shuffle操作,根据join条件对数据进行重新分布,shuffle操作需要网络IO/磁盘IO操作,若在数据量较大并且分布不均匀会导致数据倾斜,对任务执行效率产生影响。其使用场景是对于两表数量都不大的场景使用 。explain 查看执行计划如下:

2. map join 也称之为mapside join, 通常应对小表关联大表情形,对common join 的优化,将小表转换成为以join条件为key的hashTable分布式缓存到各个节点上去,然后map 操作扫描大表数据,每读取一条记录便从hashTable查询相对应的记录输出。由此可见map join 是使用通过空间来换取时间的优化方式,即使用内存消耗来代替shuffle、reduce操作。

小表的定义:set hive.mapjoin.smalltable.filesize=25000000; 认为小于等于这个数据的表都是小表

开启map join: set hive.auto.convert.join = true; 若满足小表条件自动将common join 转换为map join

explain 查看执行计划如下:

3. smb join 全称为Sorted Merge Bucket Map Join,若关联量表的数据量都很大,使用map join将其中一表的数据全部加载到内存中,对内存消耗很大,很容易导致内存溢出而任务失败 ,使用common join方式执行shuffle操作,会有大量的数据发生网络IO/磁盘IO,并且在数据分布不均匀的情况下很容易导致数据倾斜,致使任务执行时间延长,smb join就是为了应对这种情形提出来的,使用分而治之的思想。

首先了解一下分桶,分桶相对于分区来说是更加细粒度的数据组织方式,分桶会将一个分区下的数据或者未分区全表数据按照分桶字段求其hash值然后对分桶数量取余决定其所在的桶,那么分区下的数据文件数或者全表文件数就是分桶的个数。分桶还有一个重要的条件就是对分桶字段进行排序,每一个桶里面的数据按照分桶字段进行升序或者降序组织,那么其整体就是一个并归排序操作。

实例如下:

代码语言:javascript复制
 set hive.enforce.bucketing=true;
  CREATE TABLE table1(
        co1 string, 
        co2 string, 
        co3 string)
       CLUSTERED BY (co1) 
     SORTED BY (co1 ASC) INTO 16 BUCKETS; //表示按照col1 升序分桶,分桶个数为16
    insert into table1
 select * from table2 cluster by co1;

表分桶应对两种情形一种是数据抽样,暂不做讨论,另外一种就是应对大表关联大表,使用分而治之思想 map join,对关联两表做成以join条件为分桶字段的表,并且按照同样的排序方式组织分桶数据,两表的分桶个数必须成整数倍数关系。在表数据关联的时候,将小表的数据加载到内存中,开启大表桶个数的map任务,并且将小表桶数据加载到与大表对应桶位置对应(相同或者成倍数关系)的map任务的内存中去,然后以map join的方式执行,这种方式与map join的区别一是数据进行过滤,并不是全数加载到内存中,二是数据是有序的,降低扫描次数,提升效率。由此看来SMB join 使用分而治之思想转换为多个小的map join 操作,规避shuffle 操作。

代码语言:javascript复制
 set hive.auto.convert.sortmerge.join=true;
       set hive.optimize.bucketmapjoin=true;
       set hive.optimize.bucketmapjoin.sortedmerge=true;
       set  hive.input.format
=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
   // 将使用SMB map join 优化任务

explain 查看执行计划如下:

0 人点赞