Hive - 两个表的高效连接

Posted

技术标签:

【中文标题】Hive - 两个表的高效连接【英文标题】:Hive - Efficient join of two tables 【发布时间】:2013-12-10 12:48:21 【问题描述】:

我正在加入 Hive 中的两个大表(一个超过 10 亿行,一个大约 1 亿行),如下所示:

create table joinedTable as select t1.id, ... from t1 join t2 ON (t1.id = t2.id);

我以相同的方式对这两个表进行了分桶,按 id 将每个表聚类为 100 个桶,但查询仍然需要很长时间。

关于如何加快速度的任何建议?

【问题讨论】:

【参考方案1】:

当您通过连接键对数据进行分桶时,您可以使用 Bucket Map Join。为此,一个表中的存储桶数量必须是另一张表中存储桶数量的倍数。可以通过在查询前执行set hive.optimize.bucketmapjoin=true; 来激活它。如果表不满足条件,Hive 将简单地执行正常的 Inner Join。

如果两个表的桶数量相同,并且数据按桶键排序,Hive 可以执行更快的 Sort-Merge Join。要激活它,您必须执行以下命令:

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

您可以在https://cwiki.apache.org/confluence/download/attachments/27362054/Hive+Summit+2011-join.pdf 下找到不同连接技术的一些可视化。

【讨论】:

我会试一试。索引对 Hive 有帮助吗? IE。如果我按 id 索引 t1 和 t2? 索引不会提高连接中的性能。它们用于检索单行,例如在WHERE id=123 中。桶是这里的最佳选择。 您可以在创建表时通过附加以下内容来指定存储桶的数量:CLUSTERED BY (id) INTO 192 BUCKETS 对不起,我读错了。列值按桶的数量进行散列。对应该具有不同值的 id 列进行分桶应确保一致性。通过使用 Bucket Map Join,Hive 对桶执行常见的 Map-side Join。所以桶的数量取决于你的表的大小和hive.mapjoin.smalltable.filesize 的值,在这种情况下,它指定了 Map-side Join 的桶的最大大小(以字节为单位)。我会建议更好地使用更多的桶,因为你不能保证均匀地填充桶。【参考方案2】:

在我看来,答案比@Adrian Lange 提供的要复杂一些。

首先你必须了解 BucketJoin 和 Sort-Merge Bucket Join (SMBJ) 之间非常重要的区别:

如前所述,要执行 bucketjoin“一个表中的桶数必须是另一表中的桶数的倍数”,此外,hive.optimize.bucketmapjoin 必须设置为 true . 发出连接,如果发生上述情况,hive 会将其转换为 bucketjoin请注意,hive 不会强制执行分桶!这意味着创建分桶表不足以将表实际分桶到指定数量的桶中,因为 hive 不会强制执行此操作,除非 hive.enforce.bucketing 设置为 true(这意味着实际上设置了桶的数量由查询的最后阶段将数据插入表中的 reducer 的数量)。 从性能方面来看,请注意,当使用 bucketjoin 时,single task 在映射器访问它并执行连接之前将“较小”表读取到分布式缓存中 -当您的表有大约 1 亿行时,此阶段可能会非常长且无效! 之后,连接将与在减速器中完成的常规连接相同。

要执行 SMBJ,除了将 hive.optimize.bucketmapjoin.sortedmerge 设置为 true 之外,两个表还必须在相同的列上具有完全相同数量的存储桶并按这些列排序。 与之前的优化一样,Hive 不会强制执行分桶和排序,而是假设您确保表实际上是分桶和排序的(不仅通过定义,而且通过设置 hive.enforce.sorting 或在插入数据时手动排序数据) - 这非常重要,因为它可能导致两种情况下的错误结果。 从性能方面来看,这种优化效率更高,原因如下:

    每个映射器都读取两个存储桶,分布式缓存加载不存在单个任务争用 正在执行的连接是合并排序连接,因为数据已经排序,效率更高。

请注意以下注意事项:

在这两种情况下set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat; 应该被执行 在这两种情况下都应在查询中应用/*+ MAPJOIN(b) */(紧跟在select 之后,其中b 是较小的表) 多少桶? 这应该从这个角度来看:考虑应该严格应用于较大的桌子,因为它从这个方向有更大的影响,而后者的配置将必须应用于较小的桌子。我认为根据经验,每个桶应该包含 1 到 3 个块,可能接近 2 个块。因此,如果您的块大小为 256MB,对我来说,在更大的表中的每个存储桶中有 ~512MB 的数据是合理的,所以这变成了一个简单的划分问题。

另外,不要忘记,仅靠这些优化并不能保证更快的查询时间。 假设您选择执行 SMBJ,这会增加在运行连接之前对 2 个表进行排序的成本 - 因此,您运行查询的次数越多,您为这个排序阶段“支付”的费用就越少。

有时,简单的连接会带来最佳性能,而上述优化都无济于事,您必须在应用程序/逻辑级别或通过调整 MapReduce / Hive 设置(如内存使用/并行等。

【讨论】:

【参考方案3】:

对于map bucket join,我认为“一个表中的桶数必须是另一表中的桶数的倍数”不是必须的标准,我们也可以有相同数量的桶。

【讨论】:

以上是关于Hive - 两个表的高效连接的主要内容,如果未能解决你的问题,请参考以下文章

hive 的 left semi join

如何在Hive中进行数据压缩以实现高效存储?

在 Hive/Spark 中高效查找大数据表的所有相关子范围

HiveQL - 大数据的高效 geoip 发现

Hive的特性

拿走不谢大数据高效查询神器--bitmap