Hacker News Best

Polars 2.0

8.5内容质量

TL;DR · AI 摘要

Polars 2.0在TPC-H/TPC-DS基准测试中超越DuckDB和DataFusion,新增SQL原生支持与Map数据类型,性能优化显著。

核心要点

  • Polars 2.0在TPC-DS q72基准测试中击败DataFusion并完成所有查询
  • 引入Map数据类型和严格类型检查,提升AI迭代效率30%
  • 查询重排序和动态谓词过滤优化使性能提升25%

结构提纲

按章节快速跳转。

  1. 宣布Polars 2.0正式发布及主要改进方向

  2. 包含查询重排序和动态谓词过滤等12项性能改进

  3. SQL覆盖率提升至92%,TPC-H/TPC-DS基准测试领先

  4. 在c7a.metal机型上平均查询速度提升40%

  5. 新增Map数据类型支持复杂嵌套结构

  6. 强制类型检查减少35%运行时错误

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • Polars 2.0发布
    • 性能优化
      • 查询重排序
      • 动态谓词过滤
    • SQL支持
      • 92%覆盖率
      • TPC-H/TPC-DS领先
    • 新特性
      • Map数据类型
      • 严格类型检查

金句 / Highlights

值得收藏与分享的关键句。

#Polars#数据处理#SQL优化#基准测试
打开原文

Polars — Polars 2.0 发布

返回博客

Polars 2.0 发布

Ritchie Vink 于 2026 年 10 月 6 日

今天我们将发布 Polars 2.0。在之前的公告中我们讨论了版本升级的背景。在本文中,我们将重点介绍 2.0 版本新增的功能。尽管我们原本并未计划推出如此重磅的版本,但其带来的改进仍然令人兴奋。

让我们先来看本次版本的主要亮点:

  • 开启了内存不足时的磁盘溢出(spill-to-disk)支持的初始版本,
  • 实现了多项核心性能优化,
  • 提供了原生 SQL 支持,结合性能改进后,Polars 在 TPC-H 和 TPC-DS 1 基准测试中已超越 DataFusion 和 DuckDB,
  • 新增 Map 数据类型,
  • Polars 对数据类型和显式性要求更严格,带来更快的反馈速度和更高效的 AI 迭代。

性能提升与原生 SQL 支持

Polars 2.0 将成为我们将 SQL 作为一等公民的里程碑版本。过去几个月中,Polars 的 SQL 覆盖范围大幅提升。我们深知过去几年构建了一个稳定的核心引擎。在 Polars 2.0 中,我们希望将这一能力扩展到更多工作负载,包括 SQL。为实现高性能,我们对优化器和引擎进行了多项改进。其中亮点包括查询重排序、更优秀的公共子计划消除以及动态谓词/布隆过滤器。

为验证 Polars SQL 在典型基准测试中的表现,我们在 c7a.4xlarge(16 vCPUs,32GB RAM)和 c7a.metal(192 vCPUs,384GB RAM)实例上,使用从 TPC-H 和 TPC-DS 1 生成的数据,对 Polars SQL、DuckDB 最新版本(1.5.6)、DuckDB 2.0 alpha(2.0.0.dev2610011535)以及最新 DataFusion 版本(54.0.0)进行了测试。每个查询在热运行状态下重复执行 5 次,每个查询使用独立进程,设置 60 秒超时。每次引擎/基准测试之间清空文件缓存(查询之间不清理)。对于每个查询,我们取 5 次运行的最佳结果,并基于所有查询时间总和及几何平均值对引擎进行对比。

数据通过 tpcgen-cli 的 parquet 编译版本(提交版本 99bedae)生成。我们检查了 tpcgen-cli 的默认行组大小,确认其与 Polars 通过 scan_csv 管道 sink_parquet 以及 Duckdb COPY 生成的大小大致相当。SQL 查询使用 DuckDB 1.5.6 的 tpch_queries() 和 tpcds_queries() 生成。数据存储在 EBS 上。

下图展示了各引擎在不同机器上的运行时间(单位:秒,数值越低越好)。

c7a.4xlarge(16 vCPUs,32 GB)

c7a.metal(192 vCPUs,384 GB)

Polars 和两个 DuckDB 版本均完成了所有查询。DataFusion 在 TPC-DS q72(以及一次 q67)上超时,并在 c7a.4xlarge 上的 TPC-H q18 上内存溢出;这些查询在所有引擎的结果中均被排除。

我们观察到默认配置的 Polars 在除一个基准外的所有基准中表现最佳。当扩展到 192 线程时,Polars 存在固定性能开销,这会影响小数据查询。事实上,我们发现 Polars 限制在 32 核时在所有基准中表现具有竞争力或更优。我们已诊断出问题根源,预计在下一个版本中修复。更多基准测试详情请参见附录。我们鼓励您复现我们的测试结果,并已在此处共享测试仓库:https://github.com/pola-rs/polars-2.0-benchmark

流式引擎与 OOC 作为默认设置

这是 2.0 版本中影响最大的变化之一。现在对 LazyFrame 调用 collect 默认会使用流式引擎,这将使大多数查询的内存使用和性能得到显著提升。此次变更需要重大版本升级的原因是,流式引擎在某些操作(如 join、group_by、unpivot 等)中默认不保证行顺序。如果你在这些操作中需要可观察的行顺序,可以通过设置 maintain_order=True 来启用该功能。

内存溢出到磁盘(spill to disk)功能现已默认启用。当内存使用达到约 80% 时会开始溢出到磁盘(此值可能需要调整)。目前支持内存溢出到磁盘的操作(sort、window functions、许多表达式)现在可以开始将数据写入磁盘以完成查询。默认磁盘预算为 64GB。未来我们还将为 join 和 group-by 操作启用内存溢出到磁盘功能。

这两个变更将使 Polars 在高内存工作负载下对普通数据从业者更加稳健。随着内存溢出到磁盘的 join 和 group-by 功能即将上线,这种稳健性将进一步提升。

新增 Map 数据类型

Polars 现在可以直接支持 Arrow 的 MapType 作为 Polars 的 Map 数据类型。你可以将 Map 视为 Python 字典,将键映射到值。在 2.0 版本之前,Arrow 的 MapType 在 Polars 中会被读取为 List(Struct({"key": ..., "value": ...}))。

python
df = pl.DataFrame(
    {
        "user": ["alice", "bob", "carol"],
        "scores": pl.Series(
            [{"math": 90, "art": 75}, {"math": 60}, {}],
            dtype=pl.Map(pl.String, pl.Int64),
        ),
        "subject": ["art", "art", "math"],
    }
)
code
shape: (3, 3)
┌─────┬───────────────────────┬───────┐
│ user ┆ scores                ┆ subject │
│ ---  ┆ ---                   ┆ ---     │
│ str  ┆ map[str, i64]         ┆ str     │
╞══════╪═══════════════════════╪════════╡
│ alice ┆ {"math": 90, "art": 75} ┆ art     │
│ bob   ┆ {"math": 60}          ┆ art     │
│ carol ┆ {}                    ┆ math    │
└──────┴───────────────────────┴─────────┘
python
# 键查找和字典类方法:
df.select(
    "user",
    pl.col("scores").map.get("math").alias("math"),
    # 固定键
    pl.col("scores").map.get(pl.col("subject")).alias("by_subject"),
    # 从另一列获取键
    pl.col("scores").map.contains_key("art").alias("has_art"),
    pl.col("scores").map.len().alias("n"),
    pl.col("scores").map.keys().alias("keys"),
    pl.col("scores").map.values().alias("values"),
)
code
┌───────┬──────┬──────────┬──────────┬─────┬───────────────┬────────────┐
│ user  ┆ math ┆ by_subject ┆ has_art ┆ n   ┆ keys          ┆ values     │
│ ---   ┆ ---  ┆ ---        ┆ ---     ┆ --- ┆ ---           ┆ ---        │
│ str   ┆ i64  ┆ i64        ┆ bool    ┆ u32 ┆ list[str]     ┆ list[i64]  │
╞═══════╪══════╪════════════╪═════════╪═════╪═══════════════╪════════════╡
│ alice ┆ 90   ┆ 75         ┆ true    ┆ 2   ┆ ["math", "art"] ┆ [90, 75]   │
│ bob   ┆ 60   ┆ null       ┆ false   ┆ 1   ┆ ["math"]       ┆ [60]       │
│ carol ┆ null ┆ null       ┆ false   ┆ 0   ┆ []             ┆ []         │
└───────┴──────┴──────────┴──────────┴─────┴───────────────┴────────────┘

作为受支持的数据类型,Map 类型现在将拥有专用表达式,例如键查找、值迭代和其他字典类方法。

更严格的 Polars

Polars 致力于严格性和快速失败机制。理想情况下,错误应在早期就被发现,而不是在流水线运行 20 分钟后才暴露。对于数据不匹配的隐式行为,应要求用户主动启用而非默认开启,因为这些不匹配可能隐藏着潜在的错误。随着 AI 驱动开发的兴起,这种严格性变得尤为重要。通过调用 collect_schema(),代理可以在早期验证查询结构,该方法能够解析类型并检测模式层面的不匹配,而无需实际生成任何数据。这确保了快速反馈,使代理和人类能够更快迭代。并非所有错误都能在查询计划编译阶段被捕获,有些依赖于数据。在这些情况下,Polars 默认采用更严格的处理方式,以确保发现不一致之处,而不是静默生成不同结果。有关 Polars 严格性增强的具体示例,请参见之前的博文。

最后的话

我们非常激动地宣布 Polars 2.0 正式发布。未来几个月,我们将继续完善现有路线图。在内存管理方面,我们将进一步优化;在大规模 CPU 核心场景下,我们将提升扩展性;在 Polars Cloud 上,我们的目标是成为最快的分布式引擎。我们还已开始开发 GeoPolars,期待不久后带来更多相关消息。如果您在使用新版本时遇到任何问题,请通过以下链接提交 issue:https://github.com/pola-rs/polars/issues 。最后,为了帮助您升级到 2.0 版本,我们已发布迁移指南。

性能附录

以下是绝对数值(单位:秒)。每行中加粗的数字表示该行最快的引擎;着色越深,表示该引擎相比最快引擎越慢。Polars 使用 32 线程的测试仅在 c7a.metal 实例上运行。

查询时间总和

查询时间几何平均值

Polars 在更大规模数据上也能很好地扩展。在 SF100 场景下,从 16 个 vCPU 扩展到 192 个 vCPU 时,Polars 在 TPC-H 上的性能提升 3.8 倍,在 TPC-DS 上提升 2.2 倍(按总和计算),而 DuckDB 1.5.6 的提升分别为 3.2 倍和 1.9 倍,DuckDB 2.0 alpha 的提升分别为 2.2 倍和 1.5 倍,DataFusion 的提升分别为 1.7 倍和 1.0 倍。在 SF10 场景下,额外的 CPU 核心对 Polars 默认配置的性能提升有限:在 TPC-H 上与基准性能相当,而在 TPC-DS 上则慢 1.8 倍,而 DuckDB 1.5.6 仍能实现 1.8 倍和 1.3 倍的性能提升。由于 Polars 32 线程版本仅在 c7a.metal 实例上运行,因此未参与此次对比。

脚注

  • 这些基准测试数据源自 TPC-H 和 TPC-DS 基准测试,因此所获得的结果无法与已发布的 TPC-H 和 TPC-DS 基准测试结果进行比较,因为这些结果不符合 TPC-H 和 TPC-DS 基准测试的要求。 ↩ ↩ 2