记录一下之前遇到的一个问题:一张几百T按天dt分区的订单表,要关联一张几M的订单类型快照表,逐月分析。
因为用的时候left join,所以订单表放在了左边,但是hive中如果要将两张表join起来的话,大表放在左边效率会比较低,如果所有表中只有一张表是小表,那么可以在最大的表通过mapper的时候将小表完全放到内存中。
Hive可以在map端执行连接过程,称为map-side JOIN,这是因为Hive可以和内存中内存中的小表进行逐一匹配,从而省略掉常规连接操作所需要的reduce过程。即使对于很小的数据集,这个优化也明显地要快于常规的连接操作,不仅减少了reduce过程,而且有时还可以同时减少map过程的执行步骤。
想要使用这个优化可以设置属性hive.auto.convert.JOIN 的值为true:
set hive.auto.convert.join=true;
create table res_table as
select
a.*,
b.type
from (
(select
*
from
order_table
where
user_id is not null
and user_id <> ''
and dt >= '2021-07-01'
and dt <= '2021-07-31') as a
left join (
select
*
from
order_type_table) as b
on a.type_id = b.type_id;
)
但是不知道为啥,执行的效率还是很满,只要join表就的花个三个小时左右,我寻思也不应该啊,我每次只取了一个月的订单数据,已经加了优化,怎么可能还跑那么久。
于是没办法,只能去求助mentor,结构被一眼打回来了,a表的where筛选条件有问题,因为是dt分区表,所以应该先筛选dt,然后再判断user_id不为空。
使用dt分区表时where筛选条件中分区字段要放在前面
改完了之后,能跑是能跑了,而且几分钟就跑完了,map和reduce都到了100%,但是最后要把数据写到表里的时候却巨慢无比,又花了好几个小时。
结果我一看数据,我的天,不太对劲,本来a表只有几亿条记录,结果写入res_table之后一下变成十几亿条记录,这妥妥的是产生笛卡尔积了啊。
然后看了一篇文章:left join 与join都会形成笛卡尔积
确认了一下,确实是产生笛卡尔积了,但是type_id应该是唯一的啊,一问才知道,原来b表是快照表,限制最新分区,我没卡dt,所以才产生了笛卡尔积。
最后改完就好啦:
set hive.auto.convert.join=true;
create table res_table as
select
a.*,
b.type
from (
(select
*
from
order_table
where
dt >= '2021-07-01'
and dt <= '2021-07-31'
and user_id <> ''
and user_id is not null) as a
left join (
select
*
from
order_type_table
where
dt = '2021-07-01') as b
on a.type_id = b.type_id;
)
|