如果你有一个运行缓慢且没有多少 I/O 的阶段,这可能是由以下因素造成的:
- 读取大量小文件
- 编写大量小文件
- 慢速 UDF
- 笛卡尔联接
- 爆炸联接
几乎可以使用 SQL DAG 识别所有这些问题。
打开 SQL DAG
若要打开 SQL DAG,请向上滚动到作业页面顶部,然后单击 关联的 SQL 查询:
现在,您应该可以看到 DAG。 如果没有,请滚动一下,应看到它:
在你继续之前,请熟悉 DAG 以及时间的消耗在哪里。 DAG 中的某些节点具有有用的时间信息,而其他节点则没有。 例如,此区块花费了 2.1 分钟,还提供了阶段 ID:
要查看此节点需要 1.4 分钟,您必须将其打开:
这些时间是累积的,因此它是所有任务花费的总时间,而不是时钟时间。 但它仍然非常有用,因为它们与时钟时间和成本相关。
熟悉 DAG 中花费的时间是有帮助的。
读取大量小文件
如果看到其中一个扫描操作程序耗费了很多时间,请打开它并检查读取的文件数量:
如果要读取数万个甚至更多的文件,则可能存在小文件问题。 文件不应小于 8MB。 小文件问题通常是通过对过多列或高基数列进行分区引起的。
如果你很幸运,你可能需要运行 OPTIMIZE。 Databricks 建议重新考虑 文件布局。
编写大量小文件
如果看到写入需要很长时间,请打开它并查找文件数以及写入的数据量:
如果要编写数万个文件或更多文件,则可能有一个小文件问题。 文件不应小于 8MB。 小文件问题通常是通过对过多列或高基数列进行分区引起的。 您需要重新考虑 文件布局,或打开 优化的写入。
慢 UDF
如果你知道自己有 UDF,或在 DAG 中看到类似这样的内容,那你可能遇到了 UDF 执行缓慢的问题:
如果你怀疑自己遇到了这个问题,请尝试注释掉你的 UDF,以查看这对数据流速度的影响。 如果 UDF 确实是花费时间的地方,则最佳选择是使用本地函数重写 UDF。 如果不可能,请考虑执行 UDF 的阶段中的任务数。 如果它小于群集中的内核数,请在使用 UDF 之前对数据帧进行repartition()
处理。
(df
.repartition(num_cores)
.withColumn('new_col', udf(...))
)
UDF 也可能因内存问题而受到影响。 请考虑每个任务可能需要将分区中的所有数据加载到内存中。 如果此数据太大,则情况可能会变得非常缓慢或不稳定。 重新分区还可以通过缩小每个任务来解决此问题。
笛卡尔联接
如果在 DAG 中看到笛卡尔联接或嵌套循环联接,则应知道这些联接非常昂贵。 确保这是你打算的,看看是否有另一种方法。
分解联接或分解
如果你看到进入节点的几行数据,而输出的数据量成倍增加,那么你可能遇到了“explode join”或“explode()”问题。
详细了解 Databricks 优化指南中的爆炸情况。