我正在加入 Hive 中的两个大表(一个超过 10 亿行,一个是大约 1 亿行),如下所示:
create table joinedTable as select t1.id, ... from t1 join t2 ON (t1.id = t2.id);
我已经以相同的方式对这两个表进行了分桶,按 id 将每个表聚类为 100 个桶,但查询仍然需要很长时间。
关于如何加快速度的任何建议?
我正在加入 Hive 中的两个大表(一个超过 10 亿行,一个是大约 1 亿行),如下所示:
create table joinedTable as select t1.id, ... from t1 join t2 ON (t1.id = t2.id);
我已经以相同的方式对这两个表进行了分桶,按 id 将每个表聚类为 100 个桶,但查询仍然需要很长时间。
关于如何加快速度的任何建议?
当您通过连接键对数据进行分桶时,您可以使用 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下找到不同连接技术的一些可视化。
在我看来,答案比@Adrian Lange 提供的要复杂一些。
首先您必须了解 BucketJoin 和 Sort-Merge Bucket Join (SMBJ) 之间非常重要的区别:
如前所述,要执行bucketjoin,“一个表中的存储桶数量必须是另一张表中存储桶数量的倍数”,此外还hive.optimize.bucketmapjoin
必须设置为true。发出连接,如果发生上述情况
,hive 会将其转换为bucketjoin ,但请注意 hive 不会强制执行分桶!这意味着创建分桶的表不足以将表实际分桶到指定数量的桶中,因为除非hive.enforce.bucketing
设置为 true,否则 hive 不会强制执行此操作(这意味着桶的数量实际上是由数量设置的在查询的最后阶段将数据插入表中的 reducer)。
从性能方面来看,请注意,当使用bucketjoin时,单个任务会在映射器访问它并执行连接之前将“较小”表读取到分布式缓存中 - 当您的表有~100m 行!
之后,连接将与在减速器中完成的常规连接相同。
要执行SMBJhive.optimize.bucketmapjoin.sortedmerge
,除了设置为 true之外,两个表都必须在相同的列上具有完全相同数量的 buckets 并按这些列排序。
与之前的优化一样,Hive 不强制执行分桶和排序,而是假设您确保表实际上是分桶和排序的(不仅根据定义,而且通过hive.enforce.sorting
在插入数据时设置或手动排序数据) - 这是非常重要,因为这两种情况都可能导致错误的结果。
从性能方面来看,这种优化效率更高,原因如下:
请注意以下注意事项:
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
/*+ MAPJOIN(b) */
应该在查询中应用 a(就在select
较小b
的表之后)另外,不要忘记这些优化本身并不能保证更快的查询时间。
假设您选择执行 SMBJ,这会增加在运行连接之前对 2 个表进行排序的成本 - 因此,您运行查询的次数越多,您为这个排序阶段“支付”的费用就越少。
有时,简单的连接会带来最佳性能,而上述优化都无济于事,您必须在应用程序/逻辑级别或通过调整 MapReduce / Hive 设置(如内存使用/并行度等)来优化常规连接过程。
我不认为它是映射桶连接的必须标准“一个表中的桶数必须是另一表中桶数的倍数”,我们也可以有相同数量的桶。