Spark中读取文件列表与直接读取路径的效率是否一致?
前置说明
你遇到的AnalysisException: Unable to infer schema for CSV报错和读取方式无关,本质是多深度分区下Spark扫描目录时如果先扫到空目录/非CSV文件,无法匹配到有效数据就会触发该错误,手动指定schema后直接读取根目录也可以规避该报错。
三种方式的性能差异
第一种:直接传入目标目录路径
spark.read.format('csv').load('/mnt/article/2021/08/09')
性能最优,Spark仅需调用1次文件系统list接口扫描目标目录下的文件,没有额外开销。只要目标目录下无多余的无关文件,该方式的执行效率是最高的。第二种:传入显式文件路径列表
性能和第一种几乎一致,数千个文件的规模下二者的差异可以完全忽略。Spark拿到路径列表后不需要再做目录扫描,直接按给定路径读取文件,唯一的额外开销只有路径列表本身的序列化传递,只有当文件规模达到十万级以上才会出现可观测的微小性能损耗。
注意:如果你是自行遍历目录生成的文件列表,要注意遍历逻辑的效率,比如Databricks环境下用dbutils.fs.ls递归遍历的效率远低于Spark原生的目录扫描逻辑,如果生成列表的过程耗时很高,和load方法本身无关,是路径生成逻辑的问题。第三种:传入通配符路径
性能略低于前两种,通配符层级越多、目录结构越复杂,Spark多层目录匹配扫描的开销就越大。如果你使用的是ADLS Gen2这类对象存储,list接口的原生开销更高,通配符扫描的性能损耗会被进一步放大。
实践建议
你目前使用的第二种方式完全可以满足需求,数千个文件的规模下不存在效率过低的问题,不需要切换到第三种方案。如果想要进一步简化代码,也可以手动定义CSV对应的StructType schema,读取时传入schema参数,即可直接读取多层级分区的根目录,不需要手动维护文件列表,性能也更好。
内容的提问来源于stack exchange,提问作者OrganicMustard

