必须显式指定engine="pyarrow"并结合列裁剪、谓词下推及分块读取:千万级Parquet文件直接pd.read_parquet()易OOM;旧版Pandas默认fastparquet不支持并行与下推,PyArrow引擎才能发挥列存优势。

直接用 pd.read_parquet() 读千万级 Parquet 文件,不加干预大概率会卡住、OOM 或白白浪费 CPU——这不是 Pandas 慢,是你没让 PyArrow 发挥作用。
必须显式指定 engine="pyarrow"
很多人装了 pyarrow 却没提速,根本原因是 Pandas 旧版本(如 1.5.x)默认用 fastparquet,而它不支持并行解码、谓词下推,对嵌套类型和时区时间戳也常报错。Pandas 2.0+ 虽默认切到 PyArrow,但显式写更稳。
- 错误写法:
pd.read_parquet("data.parquet")(可能 fallback 到fastparquet) - 正确写法:
pd.read_parquet("data.parquet", engine="pyarrow") - 验证是否生效:读取后检查
df.dtypes中字符串列是否为string(PyArrow 引擎)而非object(fallback 状态)
只读需要的列 + 过滤条件必须下推
Parquet 是列存,全量读等于放弃最大优势。千万级文件里只查 3 列?不裁剪就多占 5–10 倍内存;有时间范围或状态过滤?不走谓词下推就得把整行组都解压再筛。
- 列裁剪:
pd.read_parquet("data.parquet", columns=["user_id", "event_time", "amount"], engine="pyarrow") - 谓词下推(注意语法是 list of lists):
filters=[("event_time", ">=", "2024-01-01"), ("status", "==", "success")] - 关键限制:
filters只对已写入统计信息(statistics)的列生效,分区列天然支持;非分区列若没 statistics,会被降级为 client-side filter(仍要读全部数据块)
超大文件别硬读,改用 ParquetDataset 分块控制
单个 Parquet 文件超过 5GB,read_parquet() 容易触发元数据加载瓶颈(尤其分区多、row group 多时),元数据本身就能占几百 MB。这时应跳过 Pandas 封装,用 PyArrow 底层 API 手动调度。
立即学习“Python免费学习笔记(深入)”;
- 先 inspect:
meta = pq.read_metadata("data.parquet")看 row group 数量和每组行数 - 分批读取 row group:
pf = pq.ParquetFile("data.parquet"); for i in range(pf.num_row_groups): table = pf.read_row_group(i); df_chunk = table.to_pandas() - 好处:内存可控、可跳过损坏或无关的 row group、便于加进度日志;坏处:需自行合并逻辑,不支持跨 row group 的
filters下推(得在 chunk 内二次过滤)
最容易被忽略的一点:PyArrow 的性能高度依赖文件本身的写入质量。如果 Parquet 是 Spark 或旧版 DuckDB 写出的,row group 大小不均、statistics 缺失、编码方式不统一,再好的读取参数也救不回 IO 效率。上线前务必用 pq.read_metadata() 和 pq.read_schema() 检查结构,而不是只盯着读取代码调参。



















