You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

准备导入DataFrame并导出Parquet时,采用列式存储是否更优?

问题解答

列式存储确实更高效

Polars底层是列式存储引擎,直接按列构建数组的方式,比先攒行式列表再转DataFrame高效得多:

  • 内存层面:同类型的列数组内存布局更紧凑,没有行式列表的内存碎片化问题,数TB级数据下能显著降低内存占用。
  • 转换开销:行式转列式时Polars需要额外做数据重组和内存拷贝,直接攒列可以跳过这一步,节省大量时间。

你的当前行式代码:

for file in files:
    decryptedData = []
    for line in file:
        # 解密逻辑
        decryptedData.append([val1a, val1b, val1c,(..)])
    df = pl.DataFrame(decryptedData, schema=columns)
    df.write_parquet(..)

改成列式后,这部分转换开销就消失了,直接用列数组构建DataFrame是原生适配Polars的。

列对齐的安全性可以保障

只要严格遵循整行处理的逻辑,就不会出现列错位的问题:

  • 源数据每行列数一致是基础前提;
  • 你的校验逻辑(if val1a is not None and val1b is not None ...)保证了只有当整行所有值都有效时,才会把对应值追加到所有列数组里——要么全加,要么全不加,所有列的长度始终保持一致;
  • 如果遇到部分值缺失的情况,不要跳过某一列,而是统一插入空值(比如None),这样所有列的长度依然对齐,Polars会自动处理空值类型。

优化后的列式代码(用字典管理列更简洁):

for file in files:
    cols = {"A": [], "B": [], "C": []}
    for line in file:
        val1a, val1b, val1c = decrypt(line)
        # 校验整行有效性,或者处理缺失值
        if all(v is not None for v in [val1a, val1b, val1c]):
            cols["A"].append(val1a)
            cols["B"].append(val1b)
            cols["C"].append(val1c)
        else:
            # 可选:插入空值保留行,或者跳过整行
            cols["A"].append(None)
            cols["B"].append(None)
            cols["C"].append(None)
    df = pl.DataFrame(cols)
    df.write_parquet(..)

额外优化建议

  1. 多进程并行输出:既然用多进程提取数据,每个进程可以直接处理完自己的文件并生成Parquet,最后DuckDB支持直接读取目录下的所有Parquet文件(duckdb.sql("SELECT * FROM 'path/to/parquets/*.parquet'")),不需要单个进程合并,能大幅提升整体效率。
  2. 预分配列数组:如果能预估每个文件的行数,可以用list的extend或者预分配固定长度的数组(比如numpy数组,Polars可以直接读取numpy数组),进一步减少内存扩容的开销。

内容的提问来源于stack exchange,提问作者bjornasm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:23:22