如何在 Spark SQL 中完成高度倾斜的连接?
How do I make my highly skewed join complete in Spark SQL?
我的连接执行如下:
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 错误,我不想不必要地向执行程序投入更多内存。如何确保在不消耗额外资源的情况下成功执行此连接?
加入盐腌
使此连接成功执行的一种策略是执行所谓的加盐连接。
在 Spark 中,盐渍连接通过将每个键有许多条目的 table 拆分成更小的部分,同时将较小的 table 分解成相等数量的副本来运行。这会产生与普通连接相同大小的输出,但对于较大的 table 任务大小较小,因此 OOM 错误的风险降低。
通过向左侧 table 添加一列从 0 到 N 的随机数并制作右侧 table 的 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 之间的数字。确保在加盐连接中展开正确的数字集!
盐的开销
- 加盐连接不一定会使您的构建速度更快。它只是给了它一个更好的成功机会。
- 如果不必要地对连接加盐,您实际上可能会开始看到性能下降。
我的连接执行如下:
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 错误,我不想不必要地向执行程序投入更多内存。如何确保在不消耗额外资源的情况下成功执行此连接?
加入盐腌
使此连接成功执行的一种策略是执行所谓的加盐连接。
在 Spark 中,盐渍连接通过将每个键有许多条目的 table 拆分成更小的部分,同时将较小的 table 分解成相等数量的副本来运行。这会产生与普通连接相同大小的输出,但对于较大的 table 任务大小较小,因此 OOM 错误的风险降低。 通过向左侧 table 添加一列从 0 到 N 的随机数并制作右侧 table 的 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 之间的数字。确保在加盐连接中展开正确的数字集!
盐的开销
- 加盐连接不一定会使您的构建速度更快。它只是给了它一个更好的成功机会。
- 如果不必要地对连接加盐,您实际上可能会开始看到性能下降。