Polars读写Parquet时use_pyarrow参数配置性能差异问题咨询
问题概述
Polars 进行 Parquet 文件读写时,use_pyarrow 参数的不同配置组合会产生显著性能差异:
- 性能最优组合:写入调用
df.write_parquet时设置use_pyarrow=True,读取调用pl.read_parquet时设置use_pyarrow=False - 性能明显下降场景:读写两端均设置
use_pyarrow=False时,Parquet 读取速度会大幅降低 - 补充测试现象:当测试代码中
np.random.randint(0, x, size=1000000)的x取值与size参数相等时,不同参数组合的性能差会出现边际递减。
复现代码
import time import polars as pl import numpy as np df = pl.DataFrame( { f"{i}": np.random.randint(0, 120, size=3000000,) for i in ("A", "B", "C", "D", "E", "F", "G", "H", 'I', "J", 'K',) } ) def repeat_read(arrow_read: bool, arrow_write: bool, n_times: int = 25) -> float: df.write_parquet('parquet', use_pyarrow=arrow_write) timings = [] for i in range(n_times): time_start = time.time() some_var = pl.read_parquet('parquet', use_pyarrow=arrow_read) timings.append(time.time() - time_start) return sum(timings) / len(timings) for i in range(3): print(f"Run {i}") read_write_false = repeat_read(arrow_read=False, arrow_write=False) print(f"Read-Write False: {read_write_false}") read_write_true = repeat_read(arrow_read=True, arrow_write=True) print(f"Read-Write Truee: {read_write_true}") read_false_write_true = repeat_read(arrow_read=False, arrow_write=True) print(f"Read False, Write True: {read_false_write_true}") read_true_write_false = repeat_read(arrow_read=True, arrow_write=False) print(f"Read True, Write False: {read_true_write_false}") print('---------------------------------------------------------\n')
基准测试结果
Read-Write False: 0.11888686180114746 Read-Write Truee: 0.14296542167663573 Read False, Write True: 0.07793953895568848 Read True, Write False: 0.16698485374450683
结论说明
该现象不属于Bug,是Polars原生Parquet实现、PyArrow Parquet实现的默认编码策略和数据转换开销共同导致的:
- 读取端开启
use_pyarrow=True时,无论文件由哪种方式写入,读取流程都会多一步「PyArrow Table 转 Polars 内存格式」的跨库拷贝转换,这部分固定开销会直接拉低读取速度,这也是read=True, write=False组合速度最慢的核心原因。 - PyArrow的Parquet写入器默认对低基数列的字典编码触发阈值更低,测试用数据集所有列取值范围都是0-119,属于极低基数整数列,PyArrow写入时会自动开启字典编码,生成的Parquet文件数据页布局更紧凑、元数据结构更适配Polars原生读取器的批量解析逻辑,因此原生读取PyArrow生成的文件时速度最快。
- 旧版本Polars原生Parquet写入器的字典编码触发策略更保守,对这类低基数整数列不会自动启用字典编码,生成的文件数据块更大、解码计算量更高,因此原生读取原生写入的文件时速度更慢。
- 观察到的「x与size相等时性能差边际递减」现象也和编码逻辑完全匹配:当x和数据量size相等时,列的基数接近100%,字典编码不会带来任何存储和解析优势,两种写入器都会退回普通整数直写编码,生成的文件结构趋同,性能差自然会收窄。
实践建议
- 若追求稳定极致性能,可直接采用
use_pyarrow=True写入、use_pyarrow=False读取的组合,无需额外调整编码参数。 - 若不想引入PyArrow依赖,可升级到最新稳定版Polars,新版本已经调整了原生Parquet写入的字典编码触发规则,低基数列的编码策略已经和PyArrow对齐,两端均使用原生实现的性能差已经基本消除。
内容的提问来源于stack exchange,提问作者zacko
相关产品推荐
相关产品推荐

