Spark读取数据时如何将数据分布到指定数量的分区?
问题解答
1. spark.sql.shuffle.partitions 对你的场景确实无效
你对官方文档的理解完全正确,该配置仅作用于join、聚合、排序等触发shuffle的算子对应的计算阶段,你的任务没有这类操作,调整该参数不会对读取Hive后的初始分区数产生任何影响。
2. 读取Hive的操作不属于shuffle
shuffle的本质是Spark为了实现算子逻辑,在不同Executor节点之间传输数据做重分布的操作,仅由特定的转换算子触发。而读取数据源产生的初始分区数,完全由数据源特性和读取配置决定,和shuffle没有任何关联。
3. 无需使用repartition/coalesce的替代方案
有两种完全可以满足你需求的轻量方案:
- 调整读取文件的分区控制参数
你可以通过修改Spark读取文件的字节阈值直接控制初始分区数量:spark.sql.files.maxPartitionBytes:控制单个分区读取的最大文件字节数,默认值为128MB。你可以根据Hive表的总大小和你期望的分区数(即内核数量)倒推设置该值即可,比如总数据量为256GB,内核数为64,就把该值设为4GB,读取出来的分区数就会和内核数匹配。- 如果表内有大量小文件,可以搭配调整
spark.sql.files.openCostInBytes(默认4MB),小于该阈值的小文件会被自动合并到同一个分区读取,避免初始分区数过多。
- 开启Spark AQE自适应优化(适用于Spark 3.0及以上版本)
开启spark.sql.adaptive.enabled = true后,搭配spark.sql.adaptive.advisoryPartitionSizeInBytes设置你期望的单个分区大小,Spark会自动在读取后合并小分区、拆分过大的分区,自动匹配到合理的分区数,不需要手动指定。
补充说明:如果你需要严格固定分区数和内核数完全对齐,repartition(目标分区数)的开销并没有你预想的高,对于无后续shuffle的简单任务来说,这仅会产生一次轻量的数据重分布,反而能保证所有计算资源被均匀占满,实际运行效率往往比只调整读取参数更高。
内容的提问来源于stack exchange,提问作者user7551211
相关产品推荐
相关产品推荐

