蜂巢地图加入。 Hive 选择更大的表存储在缓存中

Posted

技术标签:

【中文标题】蜂巢地图加入。 Hive 选择更大的表存储在缓存中【英文标题】:Hive Map Join. Hive picking the bigger table to store in cache 【发布时间】:2016-10-24 17:34:33 【问题描述】:

我设置了以下属性。

set hive.auto.convert.join=true;
set hive.optimize.ppd=true;

表 A 有 2500 万条记录。表 B 有 4400 万条记录。但是 where 子句存在条件,它在表 B 上具有过滤器。因此,在应用过滤器后,记录数下降到 200 万。

HIVE 选择表 A,而不是处理表 B 的映射连接。2500 万条记录缓存到所有数据节点中。

下面是使用的查询

select col1,col2,col3,col4 
    from table_A a 
    join
   table_B c
    on
    a.account_number=c.account_number and c.ins_date between '$date_6' and '$date_cur'.

应该怎么做才能确保 HIVE 缓存表 B?

在更大的表上包含流表提示后进行计划-

阶段依赖性: 第 4 阶段是根阶段 Stage-3 取决于阶段: Stage-4 阶段 0 取决于阶段:阶段 3 舞台计划: 阶段:第四阶段 地图减少本地工作 别名 -> 映射本地表: b 获取运算符 限制:-1 别名 -> 映射局部运算符树: b 表扫描 别名:b 统计:行数:23894045 数据大小:7048743275 基本统计:COMPLETE 列统计:无 哈希表接收器运算符 条件表达式: 0 cm_mac_fin wan_mac 重启 重启 day_id 1 部门 地区 键: 0 cm_mac_fin(类型:字符串) 1个mac(类型:字符串) 阶段:阶段 3 地图缩减 地图运算符树: 表扫描 别名:一 统计:行数:2599797 数据大小:678547017 基本统计:COMPLETE 列统计:无 映射连接运算符 条件图: 左外连接0到1 条件表达式: 0 cm_mac_fin wan_mac 重启 重启 day_id 1 mac division region 键: 0 cm_mac_fin(类型:字符串) 1个mac(类型:字符串) 输出列名:_col0、_col1、_col2、_col3、_col4、_col8、_col9、_col10 统计信息:行数:26283450 数据大小:7753617770 基本统计信息:COMPLETE 列统计信息:NONE 选择运算符 表达式:_col0(类型:字符串)、_col1(类型:字符串)、_col2(类型:int)、_col3(类型:int)、_col4(类型:日期)、_col8(类型:字符串)、_col9(类型:字符串) , _col10(类型:字符串) 输出列名:_col0、_col1、_col2、_col3、_col4、_col5、_col6、_col7 统计信息:行数:26283450 数据大小:7753617770 基本统计信息:COMPLETE 列统计信息:NONE 文件输出运算符 压缩:假 统计信息:行数:26283450 数据大小:7753617770 基本统计信息:COMPLETE 列统计信息:NONE 桌子: 输入格式:org.apache.hadoop.mapred.TextInputFormat 输出格式:org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat serde:org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe 本地工作: 地图减少本地工作 执行方式:矢量化 阶段:Stage-0 获取运算符 限制:-1 处理器树: 列表接收器

在较小的表上包含地图连接提示后进行计划-

阶段依赖性: 第 4 阶段是根阶段 Stage-3 取决于阶段: Stage-4 阶段 0 取决于阶段:阶段 3 舞台计划: 阶段:第四阶段 地图减少本地工作 别名 -> 映射本地表: b 获取运算符 限制:-1 别名 -> 映射局部运算符树: b 表扫描 别名:b 统计:行数:23894045 数据大小:7048743275 基本统计:COMPLETE 列统计:无 哈希表接收器运算符 条件表达式: 0 cm_mac_fin wan_mac 重启 重启 day_id 1 部门 地区 键: 0 cm_mac_fin(类型:字符串) 1个mac(类型:字符串) 阶段:阶段 3 地图缩减 地图运算符树: 表扫描 别名:一 统计:行数:2599797 数据大小:678547017 基本统计:COMPLETE 列统计:无 映射连接运算符 条件图: 左外连接0到1 条件表达式: 0 cm_mac_fin wan_mac 重启 重启 day_id 1 mac division region 键: 0 cm_mac_fin(类型:字符串) 1个mac(类型:字符串) 输出列名:_col0、_col1、_col2、_col3、_col4、_col8、_col9、_col10 统计信息:行数:26283450 数据大小:7753617770 基本统计信息:COMPLETE 列统计信息:NONE 选择运算符 表达式:_col0(类型:字符串)、_col1(类型:字符串)、_col2(类型:int)、_col3(类型:int)、_col4(类型:日期)、_col8(类型:字符串)、_col9(类型:字符串) , _col10(类型:字符串) 输出列名:_col0、_col1、_col2、_col3、_col4、_col5、_col6、_col7 统计信息:行数:26283450 数据大小:7753617770 基本统计信息:COMPLETE 列统计信息:NONE 文件输出运算符 压缩:假 统计信息:行数:26283450 数据大小:7753617770 基本统计信息:COMPLETE 列统计信息:NONE 桌子: 输入格式:org.apache.hadoop.mapred.TextInputFormat 输出格式:org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat serde:org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe 本地工作: 地图减少本地工作 执行方式:矢量化 阶段:Stage-0 获取运算符 限制:-1 处理器树: 列表接收器

【问题讨论】:

【参考方案1】:

Hive 内部使用多个因素来确定缓存表和流表以进行连接:

它根据配置标志 (hive.auto.convert.join.noconditionaltask, hive.auto.convert.join.noconditionaltask.size, hive.mapjoin.smalltable.filesize) 将查询转换为映射连接。 大小配置使用户能够控制内存中可以容纳的大小表。 假设 n 个表参与连接,则连接的 n-1 个表必须放入内存中才能使映射连接优化生效。 当 n=2 且参数 hive.auto.convert.join 设置为 true 时,hive 会进行 mapjoins 并缓存小于 hive.mapjoin.smalltable.filesize 此参数的表。

在您的情况下,您可以显式指定缓存表而不是配置单元来确定它:

select /*+MAPJOIN(c)*/ col1,col2,col3,col4 
    from table_A a 
    join
   table_B c
    on
    a.account_number=c.account_number and c.ins_date between '$date_6' and '$date_cur'.

【讨论】:

嗨 Rahul- 如果我们执行左连接而不是内连接,提示会起作用吗?我需要缓存外部表。 是的,如果是左连接,您需要一个表中的所有记录,因此该表应该是流式的,而另一个连接表可以是缓存或内存中的。 select /*+MAPJOIN(a)*/ col1,col2,col3,col4 from table_A a left join table_B c on a.account_number=c.account_number and c.ins_date between '$date_6' and '$date_cur'。表 A 比表 B 小,因此我希望表 A 被缓存。我给出了提示,但配置单元仍然没有缓存表 A。它正在缓存表 B。知道为什么吗? 试试这个: select /*+ STREAMTABLE(c) */ col1,col2,col3,col4 from table_A a left join ( select * from table_B cins_date between 'pqr' and 'xyz') c on a.account_number=c.account_number。 还分享两个查询的解释命令响应。解释 select /*+MAPJOIN(a)*/ col1,col2,col3,col4 from table_A a left join table_B c on a.account_number=c.account_number和 '$date_6' 和 '$date_cur' 之间的 c.ins_date【参考方案2】:

在加入前将 where 子句移至 CTE。

WITH b as (
  SELECT col1,col2,col3,col4 
  FROM table_B
  WHERE ins_date between '$date_6' and '$date_cur'
)
SELECT col1,col2,col3,col4 
FROM table_A a join b
on a.account_number = b.account_number;

这样,连接右侧的 b 只有 200 万条记录,因此被加载到 RAM 中。

【讨论】:

以上是关于蜂巢地图加入。 Hive 选择更大的表存储在缓存中的主要内容,如果未能解决你的问题,请参考以下文章

在火花中加入两个存在于蜂巢中的表

蜂巢加入失败 mr.MapredLocalTask

蜂巢中的表连接失败

如何像蜂巢中的地图一样将两列合并为一列?

蜂巢分区表上的火花行为

蜂巢订单不工作