Spark SQL读取Hive表时,原表与新表分区数为何不一致?
为啥读取原Hive表和新写入表的分区数不一样?
嘿,这个问题我之前也碰到过,其实核心是Spark读取和写入Hive表时的分区逻辑不是完全对应的,我给你拆解下可能的原因:
1. 存储格式差异导致文件大小变化
你写入新表时用的是Parquet格式,但原表src_table可能是其他格式(比如TextFile、ORC)。不同格式的压缩率、存储结构差异很大:
- 比如TextFile是行式存储,压缩率低,文件体积大;Parquet是列式存储,压缩率高,相同数据的文件体积会小很多。
- Spark读取表时的分区数,是结合HDFS BlockSize和实际文件大小来计算的:一个大于BlockSize的文件会被拆分成多个分区,小文件则可能被合并。当新表的文件大小和原表差异明显时,读取时的分区数自然就不一样了。
2. Spark写入时的配置影响了输出文件数
Spark写入数据时,有几个配置会直接影响生成的文件数量,进而影响后续读取的分区数:
spark.sql.files.maxRecordsPerFile:限制每个输出文件的最大记录数,如果原DataFrame的一个分区记录数超过这个值,会被拆分成多个文件,导致新表的文件数变多。spark.sql.adaptive.enabled:如果开启了自适应执行,Spark会在写入时自动合并小分区,减少输出文件数,这会让新表的文件数比原DataFrame的分区数少。spark.sql.shuffle.partitions:如果你的写入操作涉及 shuffle(比如有聚合、排序),这个配置会决定 shuffle 后的分区数,不过你这里是直接写数据,大概率不涉及,但也可以留意下。
3. 原表是分区表,写入时未保留分区结构
如果src_table是Hive分区表(比如按日期、地域分区),你用select *读取时,Spark会扫描所有分区下的文件,生成的分区数是所有分区文件合并/拆分后的数量。但你写入new_table时没有用partitionBy指定分区,新表会变成无分区表,所有数据会被写入到同一个目录下,生成的文件数和原表的分区文件数逻辑完全不同,读取时的分区数自然就不一样了。
4. 小文件合并策略的差异
如果原表存在大量小文件,Spark读取时会通过spark.sql.files.maxPartitionBytes(默认128MB)自动合并小文件,生成较少的分区。但你写入新表时,如果没有开启小文件合并,会按原DataFrame的分区数生成文件,这些文件可能还是小文件;后续读取新表时,如果合并策略不同(比如配置了不同的maxPartitionBytes),就会生成和原表不同的分区数。
怎么让分区数一致?
如果你希望读取新表时的分区数和原表一致,可以试试这些方法:
- 写入前手动指定分区数:
newData.repartition(data.rdd.getNumPartitions) .write.mode("overwrite").format("parquet").saveAsTable("new_table") - 调整读取配置,让两次读取的合并策略一致:比如把
spark.sql.files.maxPartitionBytes设置成相同的值,确保小文件合并逻辑一样。 - 如果原表是分区表,写入新表时用
partitionBy保留相同的分区字段,让存储结构和原表一致。
内容的提问来源于stack exchange,提问作者cat
相关产品推荐
相关产品推荐

