Python加载读取多份超大型CSV文件的最优方案是什么?
大规模CSV数据集关联操作优化方案
2.34亿行规模的数据集关联操作卡顿、报错,核心原因通常是行存CSV扫描效率低、关联键未预校验/预排序、分区策略不合理、执行引擎优化不足,可按以下优先级调整方案:
第一步先做预处理,统一转换为列式存储格式
CSV是行存储格式,关联操作需要全量扫描所有字段,IO开销极高,先批量转成Parquet格式,同时提前做字段类型校验、关联键预分区,能解决90%的类型不匹配报错、降低后续操作的IO开销:import dask.dataframe as dd # 批量读取CSV时提前指定所有字段类型,尤其是关联键的类型,避免隐式转换报错 ddf = dd.read_csv("./csv_file_path/*.csv", dtype={"join_key": "str", "amount": "float64"}) # 按后续需要关联的键做索引、分区,分区数建议设置为CPU核心数的2-3倍 ddf = ddf.set_index("join_key", npartitions=200) # 持久化为Parquet格式,压缩比高、列存扫描效率是CSV的10倍以上 ddf.to_parquet("./preprocessed_main_data.parquet", engine="pyarrow", compression="zstd")第二步替换执行引擎,优先选择DuckDB或Polars做关联操作
这两款引擎对关联操作的原生优化远高于vaex和默认Pandas后端的Dask,内存控制也更稳定:- 如果内存可以容纳至少50%的全量数据,优先用DuckDB走SQL关联,代码示例:
import duckdb # 内存不足时可以把:memory:替换为本地文件路径,用磁盘交换做大规模计算 conn = duckdb.connect(database=':memory:') # 不需要全量加载数据到内存,直接读Parquet文件执行关联 join_result = conn.execute(""" SELECT a.*, b.* FROM read_parquet('./preprocessed_main_data.parquet/*') a INNER JOIN other_dataframe b ON a.join_key = b.join_key """).df() - 如果偏好Python dataframe式操作,优先用Polars的懒加载模式:
import polars as pl # 懒加载数据,仅生成执行计划,不实际加载进内存 main_df = pl.scan_parquet("./preprocessed_main_data.parquet/*") other_df = pl.scan_csv("./other_df_path/*.csv") # 自动做谓词下推、关联优化,执行计算后返回结果 join_result = main_df.join(other_df, on="join_key", how="inner").collect()
- 如果内存可以容纳至少50%的全量数据,优先用DuckDB走SQL关联,代码示例:
如果必须保留Dask技术栈,调整关联参数减少报错和耗时
关联前确保两个Dask DataFrame按关联键做索引、且分区数一致,关联时指定shuffle策略避免内存溢出:ddf_main = ddf_main.set_index("join_key", npartitions=150) ddf_other = ddf_other.set_index("join_key", npartitions=150) join_result = ddf_main.merge(ddf_other, left_index=True, right_index=True, shuffle="disk")
内容的提问来源于stack exchange,提问作者Caue
相关产品推荐
相关产品推荐

