跳转至

Hive大表join大表如何调优

前言

在Hive中,优化器会根据统计信息决定是将大表放在前面(Join的左边)还是小表放在前面。通常,优化器会选择数据量较小的表作为驱动表(小表作为左边),因为这样可以减少内存消耗并提高效率。

但是,如果你有特定的需求,比如你知道大部分数据能快速过滤掉,希望减少任务的执行时间,那么你可以强制指定某个表作为小表。在Hive中,可以使用/*+ MAPJOIN(table_name) */ 注释来强制将一个大表作为小表处理。

例如,如果你想要将 small_table 作为小表(将小表加载到内存中):

SELECT /*+ MAPJOIN(small_table) */
  a.column1, a.column2, b.column1, b.column2
FROM
  small_table a
JOIN
  big_table b
ON
  a.common_column = b.common_column;

一、调优思路

1、SQL优化

1.1 大小表join

  1. mapjoin:小表使用mapjoin,或者强制hint
  2. 将大表放后头:原因:Hive假定查询中最后的一个表是大表。它会将其它表缓存起来,然后扫描最后那个表。因此通常需要将小表放前面,或者标记哪张表是大表:/*streamtable(table_name) */
  3. 过滤无效值:空值、不使用的字段等
  4. 不能过滤的空值:将空值转化为随机数避免数据倾斜

1.2 大大表join

1)创建第二张大表

create table bigtable2(
    id bigint,
    t bigint,
    uid string,
    keyword string,
    url_rank int,
    click_num int,
    click_url string)
row format delimited fields terminated by '\t';

load data local inpath '/opt/module/data/bigtable' into table bigtable2;

2)测试大表直接JOIN

insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable a
join bigtable2 b
on a.id = b.id;

测试结果:Time taken: 72.289 seconds

3)创建分桶表1

create table bigtable_buck1(
    id bigint,
    t bigint,
    uid string,
    keyword string,
    url_rank int,
    click_num int,
    click_url string)
clustered by(id)
sorted by(id)
into 6 buckets
row format delimited fields terminated by '\t';

load data local inpath '/opt/module/data/bigtable' into table bigtable_buck1;

4)创建分桶表2,分桶数和第一张表的分桶数为倍数关系

create table bigtable_buck2(
    id bigint,
    t bigint,
    uid string,
    keyword string,
    url_rank int,
    click_num int,
    click_url string)
clustered by(id)
sorted by(id)
into 6 buckets
row format delimited fields terminated by '\t';

load data local inpath '/opt/module/data/bigtable' into table bigtable_buck2;

5)设置参数

set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;

6)测试

insert overwrite table jointable
select b.id, b.t, b.uid, b.keyword, b.url_rank, b.click_num, b.click_url
from bigtable_buck1 s
join bigtable_buck2 b
on b.id = s.id;

测试结果:Time taken: 34.685 seconds


2、insert overwrite替换union all

使用insert overwrite替代union all可以提高执行效率。


3、排序order by换位sort by

在不需要全局排序的情况下,使用sort by替代order by可以减少单个Reduce的任务负担,提高性能。


4、并行执行

启用并行执行可以充分利用集群资源,减少任务总执行时间。

set hive.exec.parallel=true;

5、数据倾斜优化

数据倾斜是Hive调优中的常见问题,主要解决方法包括:

  1. 空值处理:将空值转化为随机数打散
  2. key扩容:对倾斜的key进行扩容处理
  3. 分而治之:将倾斜key和非倾斜key分开处理,最后union all

6、小文件优化

小文件过多会导致NameNode内存压力增大,同时也会影响MapReduce任务的执行效率。解决方法包括:

  1. 合并小文件:使用Hive的合并功能
  2. 调整输入格式:使用CombineHiveInputFormat
  3. 调整输出:减少输出文件数量

二、实战

2.1 场景

(场景描述待补充)

2.2 限制所需的字段,间接mapjoin

通过限制SELECT中的字段,可以减少数据传输量,间接实现mapjoin的效果。

2.3 解决异常值倾斜,如NULL加随机数打散

当JOIN键中存在大量NULL值时,会导致数据倾斜。解决方法是将NULL值转换为随机数:

SELECT /*+ MAPJOIN(a) */
  a.id, a.name, b.score
FROM (
  SELECT 
    CASE WHEN id IS NULL THEN CAST(RAND() * 1000 AS BIGINT) ELSE id END AS id,
    name
  FROM table_a
) a
JOIN table_b b
ON a.id = b.id;

2.4 扩容解决数据倾斜

2.4.1 客户表扩大N倍

将客户表扩容N倍,减少数据倾斜。

2.4.2 部分倾斜key扩容,大卖家扩容

针对特定的大卖家key进行扩容处理。

2.4.3 推荐:分而治之:倾斜和非倾斜再union all

将倾斜的key和非倾斜的key分开处理,最后通过union all合并结果。这是推荐的最佳实践。