select Seller_srar, count(order_id) as ordre_cnt
from (
select order_id,seller_id
from dwd_sls_fact_detail_table
where partition_value ='20170101'
) a
Left outer join(
select seller_id,seller_star
from dim_seller
where partition_value='20170101'
) b
on a.seller_id = b.seller_id
group by b.seller_star;
但正如上述所言,现实世界的二八准则将导致订单集中在部分供应商上,而好的供应商的评级通常会更高,此时更加剧了数据倾斜的程度。如果不加以优化,上述 SQL 将会耗费很长时间,甚至运行不出结果!
通常来说,供应商是有限的,比如上千家、上万家,数据量不会很大,而销售明细事实表比较大,这就是典型的大表 join 小表问题,可以通过 mapjoin 的方式来优化,只需添加 mapjoin hint
即可,优化后的 SQL 如下:
select /\*+mapjoin(b)\*/ Seller_srar, count(order_id) as ordre_cnt
from (
select order_id,seller_id
from dwd_sls_fact_detail_table
where partition_value ='20170101'
) a
Left outer join(
select seller_id,seller_star
from dim_seller
where partition_value='20170101'
) b
on a.seller_id = b.seller_id
group by b.seller_star;
/*+mapjoin(b)*/
即 mapjoin himt
,如果需要 mapjoin 多个表,则格式为/*+mapjoin(b,c,d)*/
。
Hive 对于 mapjoin 是默认开启的,设置参数为:
Set hive.auto.convert.join=ture;
mapjoin 优化是在 Map 阶段进行 join ,而不是像通常那样在 Reduce 阶段按照 join 列进行分发后在每个 Reduce 任务节点上进行 join ,不需要分发也就没有倾斜的问题,相反 Hive 会将小表全量复制到每个 Map 任务节点(对于本例是 dim_seller ,当然仅全量复制 b表 sql 指定的列),然后每个 Map 任务节点执行 lookup 小表即可。
从上述分析可以看出,小表不能太大,否则全量复制分发得不偿失。
- 实际上 Hive 根据参数
hive.mapjoin.smalltable.filesize
( 0.11.0 本后是hive.auto.convert.join.noconditionaltask.size
)来确定小表的大小是否满足条件(默认 25M)。 - 实际中此参数值所允许的最大值可以修改,但是一般最大不能超过 1GB (太大的话 Map 任务所在的节点内存会撑爆, Hive 会报错 。另外需要注意的是, HDFS 显示的文件大小是压