Impala 如何确定 Join 策略

本文缘起社区的一个提问,正好也想要了解其计算逻辑。

SQL联结查询中右表被广播的 “判断条件”,左表与右表的数据量比例差多少右表才被广播?

有关Join查询的注意事可以参考:Join查询的性能注意事项

介绍

Impala 查询计划员会为执行 Join 查询而在不同技术之间选择,这取决于表的绝对和相对大小。Broadcast joins 是默认设置,其中右侧表被认为小于左侧表,而其内容将发送到查询中涉及的所有其他节点。替代方法被称为 partitioned join ,这更适合于大概同等大小的较大表的名称。使用此方法,每个表的各个部分将发送到相应的其他节点,在这些节点中可以并行处理行的子集。选择广播或分区 join 还取决于通过 COMPUTE STATS 语句收集的合并中所有表可用的统计信息。

查看哪种 join 策略用于特定查询,请为该查询发出一个 EXPLAIN 语句。如果发现查询使用广播 join,并且您知道通过基准测试知道分区 join 会更有效,反之亦然,那么向此查询添加提示以指定要使用的精确 join 机制。

影响因素:

统计信息

如果表或列的统计信息对合并中的一些表不可用,Impala 仍然会利用可用信息对表重新排序。带有统计信息的表位于合并订单的左侧,并根据整体大小和基数的成本按降序排列。不带有统计信息的表按零大小对待,也就是说将它们始终放在合并订单的右侧。

利用 STRAIGHT_JOIN 覆盖 Join 重新排序

如果 Impala 合并查询由于统计信息过期或意外数据分发而效率低下,您可以在使用 STRAIGHT_JOIN 关键字前先立即使用 SELECT 关键字从而让 Impala 避免对合并表重新排序。STRAIGHT_JOIN 关键词将关闭 Impala 内部执行的合并子句重新排序操作,并生成依赖于在查询文本中以最佳方式进行排序的合并子句的计划。

查询提示

/* +BROADCAST *//* +SHUFFLE */ 提示可控制合并查询的执行策略。在查询的 JOIN 关键词后面指定以下其中一种结构:

  • /* +SHUFFLE */ - 让合并操作使用"分区"技术,该技术可使用用散列算法分割这两个表格中对应的行,并将行的子集发送给其他行以进行处理。(关键字 用于表示"已分区合并",由于这种类型的合并与"已分区表"不相关。)由于当表和索引统计信息不可用时可替代"广播"合并机制为默认选项,您可能在广播合并不适用的情况下使用该查询提示;通常,已分区的合并对大小相似的较大表之间的合并更为有效。
  • /* BROADCAST] - 让使用"广播"技术的合并操作,该操作指将右侧表中的所有内容发送到处理合并时涉及的所有节点。当表和索引统计信息不可用时,这是默认操作模式,因此通常只有过时的元数据导致 Impala 错误地选择分区合并操作时您才用得到。通常情况下,当一个表格比另一个表格小得多的情况下,广播合并才更为高效。(将较小的表放在 运算符的右侧。)

查询选项

BROADCAST_BYTES_LIMIT 广播输入大小的限制

DEFAULT_JOIN_DISTRIBUTION_MODE 此选项确定当联接查询中涉及的任何表缺少统计信息时,Impala使用的联接分布。

如何确定 Join 策略

与主流的数据库和数仓查询引擎一样,Impala 也是基于代价模型进行执行计划优化(CBO)。只有获取足够的统计信息,才能支撑 Impala 选取较优的执行计划。

本节分析 Join 的计算方式,以解文章开始提出的问题。对于这两种 join 类型,总成本计算为通过网络发送的数据量,加上插入到哈希表中的数据量。

1. 计算两种 join 成本:

能计算的前提是有统计信息,否则都是 -1.

broadcast:将右侧 Fragment 输出发送到左侧的每个节点,并在节点构建哈希表。

计算:(右侧Fragment 数据大小 + 哈希表大小)* 左侧实例数

// rhsDataSize 是咋计算的呢?
rhsDataSize = Math.round(rhsTree.getCardinality() * ExchangeNode.getAvgSerializedRowSize(rhsTree));
// rhsTree.getCardinality() :右侧 Fragment 的基数,计算方式是
// ExchangeNode.getAvgSerializedRowSize(rhsTree) :返回序列化以通过 exchange 发送的“ exchInput”产生的平均行大小,值为平均行大小的1.1倍

// 广播成本
broadcastCost = 2 * rhsDataSize * leftChildNodes;

repartition:左右侧 Fragment 都在联结 exprs 上进行了分区(EqJoinConjuncts 等值连接词),并使用右侧 Fragment 的输出构建了一个哈希表。

计算:左右侧 Fragment 网络成本 + 哈希表大小(使用的是右侧 Fragment 的输出)

// 网络发送成本
// 如果只有数据分区参与联结,lhsHasCompatPartition 是 true,说明不需要进行网络传输。
// lhsHasCompatPartition = analyzer.setsHaveValueTransfer(lhsDataPartitionExprs, lhsJoinExprs, false);
// 左侧网路成本
double lhsNetworkCost = (lhsHasCompatPartition) ? 0.0 : Math.round(lhsTree.getCardinality() * ExchangeNode.getAvgSerializedRowSize(lhsTree));
// 右侧网络成本
double rhsNetworkCost = (rhsHasCompatPartition) ? 0.0 : rhsDataSize;

// 分区成本
partitionCost = Math.round(lhsNetworkCost + rhsNetworkCost + rhsDataSize);

广播成本 = 2 * 右侧数据大小 * 左侧实例数;
分区成本 = 左侧数据大小 + 右侧数据大小 + 右侧数据大小

换算之后:左侧数据大小 vs 左侧实例数 * 右侧数据大小 ≈ 左侧单个实例数据量 vs 右侧数据大小 ≈ 左侧平均文件大小 vs 右侧数据大小

todo: Impala 如何确定执行任务的实例数

2. 计算分布模式,决定使用哪种分布模式

注:重点是第 4 点,这块是根据统计数据算出来的分布模式,由此可以回答文章开头提出的问题。<

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值