資料與儲存 2026 年 10 月 7 日

2026-10-07 Polars 2.0 預設改走 streaming,不保證列順序

primary=https://pola.rs/posts/release-polars-2/ primary=https://docs.pola.rs/releases/upgrade/2/ primary=https://github.com/pola-rs/polars-2.0-benchmark

Polars 2.0 預設改走 streaming,不保證列順序

Polars 官方部落格 · 2026-10-06 · Ritchie Vink

Polars 2.0 把 LazyFrame.collect() 的 engine="auto" 從 in-memory 引擎改成 streaming 引擎,而 streaming 引擎對 join、group_by、unpivot 等操作不保證列順序。這是它必須升大版號的原因,也是升級後最容易悄悄改變結果的地方。

同一版還預設開啟 out-of-core(溢寫到磁碟)、把 SQL 列為第一級功能,並新增 Map dtype。官方另附升級指南。

原本的問題

1.x 的 lazy 查詢預設走 in-memory 引擎,整份資料要載進記憶體,遇到大資料就容易 OOM;streaming 引擎雖然存在,但要自己指定。結果是多數使用者吃不到 streaming 的記憶體與效能優勢。官方說明,改成預設後多數查詢的記憶體與效能都會大幅改善。

代價是順序。in-memory 引擎的輸出順序恰好穩定,很多程式碼其實默默依賴這個「附帶行為」,卻從沒寫過 sort。

核心改動

預設引擎切換。依升級指南,collect 與 collect_async 仍是 engine="auto",但 lazy 查詢現在解析為 streaming。eager 的 DataFrame 操作不受影響,sink_* 本來就走 streaming,也不受影響。連 pl.sql(..., eager=True) 與 SQLContext.execute(eager=True) 也改走 LazyFrame.collect()。

升級指南對 join 的警告特別值得看,因為「查詢看起來跟順序無關」:

# 2.0 起,左表列順序不保證保留
left.join(right, on="k", how="left").collect()

# 需要左表順序時明確指定
left.join(right, on="k", how="left", maintain_order="left").collect()

# 整體退回舊引擎(全域 / 單一查詢 / 環境變數)
pl.Config.set_engine_affinity("in-memory")
lf.collect(engine="in-memory")
# POLARS_ENGINE_AFFINITY=in-memory

Out-of-core 預設開啟。發布文章指出,記憶體用到約 80% 時開始溢寫,預設磁碟額度為 64GB,目前支援 sort、window function 與許多 expression;join 與 group-by 的 out-of-core 列在後續計畫。

SQL 與效能。官方以衍生自 TPC-H 與 TPC-DS 的資料,在 c7a.4xlarge(16 vCPU)與 c7a.metal(192 vCPU)上,對比 DuckDB 1.5.6、DuckDB 2.0 alpha 與 DataFusion 54.0.0。結果是 Polars 預設設定在除一項外的所有 benchmark 都最快。這是廠商自己跑的結果,且官方坦承 192 執行緒下有固定開銷,小資料查詢反而吃虧,Polars 限制在 32 核時才在所有 benchmark 中持平或領先。測試腳本已公開,可自行重跑。

其他破壞性改動

  • pl.concat(how="horizontal"):過去高度不同時會用 null 補齊,現在直接丟 ShapeError;要舊行為改用 how="horizontal_extend"。
  • pl.read_csv 改為 pl.scan_csv(...).collect(),n_threads、batch_size、sample_size、rechunk 被移除;schema_overrides 用 list 時必須涵蓋檔案所有欄位。
  • pl.read_ipc 移除 memory_map 與 rechunk 參數,傳入會得到 TypeError。
  • LazyFrame.profile() 被移除,理由是 streaming 引擎並行執行,各節點計時會誤導;開源版暫無替代品。
  • show_graph() 的 plan_stage 預設從 "ir" 改為 "physical",要舊輸出需傳 plan_stage="ir"。

新的 Map dtype

Polars 直接支援 Arrow 的 MapType。2.0 以前讀進來是 List(Struct({"key": ..., "value": ...})),要查 key 得自己展開;現在有 pl.Map(pl.String, pl.Int64),並提供 map.get、map.contains_key、map.len、map.keys、map.values。

影響範圍

最需要檢查的是依賴列順序的 pipeline:lazy 查詢裡做了 left join 後直接按位置對齊的程式碼、group_by 後取「第一筆」的程式碼、把輸出寫成快照做 diff 的測試。升級指南用 Danger 標示這類改動「可能悄悄改變 pipeline 結果」,因此測試要先跑一輪,順序敏感處補 sort 或 maintain_order。

另外,呼叫 profile() 的效能分析腳本會直接丟 AttributeRemovedError;使用 pl.read_csv 舊參數的 ETL、以及 concat 水平串接長度不一的 DataFrame 的程式,也都會在升級後立即報錯,這類錯誤反而是好的:失敗得很明顯。

容器與 CI 的使用者要留意 spill:預設 64GB 的磁碟額度,在小容量的臨時磁碟上可能不夠;官方也說 80% 的門檻「可能需要調整」。若暫時不想動,可用 POLARS_ENGINE_AFFINITY=in-memory 先退回舊引擎,再逐步修正。

原始來源:Release of Polars 2.0、Polars 2.0 升級指南、polars-2.0-benchmark


End of article
0
Would love your thoughts, please comment.x
()
x