2

我的加入执行如下:

SELECT
  left.*, 
  right.*
FROM `/foo/bar/baz` AS left
JOIN `/foo2/bar2/baz2` AS right
ON left.something = right.something

数据集: /foo/bar/baz

+-----------+-------+
| something | val_1 |
+-----------+-------+
| a         |     1 |
| a         |     2 |
| a         |     3 |
| a         |     4 |
| a         |     5 |
| a         |     6 |
| a         |   ... |
| a         |   10K |
| b         |     1 |
| b         |     2 |
| b         |     3 |
+-----------+-------+

数据集:/foo2/bar2/baz2

+-----------+-------+
| something | val_2 |
+-----------+-------+
| a         |     1 |
| a         |     2 |
| b         |     1 |
| b         |     2 |
| b         |     3 |
+-----------+-------+

我的执行程序出现 OOM 错误,我不想不必要地向执行程序投入更多内存。如何在不消耗额外资源的情况下确保此连接成功执行?

4

1 回答 1

6

盐渍连接

使此联接成功执行的一种策略是执行所谓的加盐联接。

加盐连接在 Spark 中通过将每个键包含许多条目的表拆分为较小的部分,同时将较小的表分解为相等数量的副本。这会产生与普通连接相同大小的输出,但较大表的任务大小较小,因此 OOM 错误的风险降低。您可以通过将一列从 0 到 N 的随机数添加到左表并制作右表的 N 个副本来对连接进行加盐。如果您将新的随机列添加到连接中,您会将最大的存储桶减少到之前大小的 1/N。

秘诀是 EXPLODE 函数。EXPLODE 是一个交叉产品:

SELECT
  left.*, 
  right.*
FROM
  (
    SELECT 
      *, 
      FLOOR(RAND() * 8) AS salt 
      FROM `/foo/bar/baz`
  ) AS left
JOIN
  (
    SELECT 
      *, 
      EXPLODE(ARRAY(0,1,2,3,4,5,6,7)) AS salt 
      FROM `/foo2/bar2/baz2`
  ) AS right
ON 
left.something = right.something 
AND left.salt = right.salt

调音

  • 你如何选择爆炸的因素?主要是受过教育的猜测。2 的幂是找到正确球场的好方法:8、16、32。
  • 一种类似的方法是在无盐作业运行时查看每个执行程序的行数。

需要注意什么

  • 确保在加盐连接时不会犯错误。这将使您丢失一小部分记录。
  • CEIL(RAND() * N)为您提供 0 到 N 之间的整数。FLOOR(RAND() * N)为您提供 0 到 N - 1 之间的数字。确保在加盐连接中分解正确的数字集!

盐的开销

  • 加盐连接并不一定会使您的构建速度更快。它只是给它一个更好的成功机会。
  • 如果您不必要地对连接进行加盐,您实际上可能会开始看到性能下降。
于 2019-12-03T15:37:51.983 回答