网易首页 > 网易号 > 正文 申请入驻

Polars 2.0扶正SQL,跑赢了 DuckDB

0
分享至



一、过去是直接崩,现在只是慢

2026 年 10 月 6 日,Polars 作者 Ritchie Vink 在官方博客挂出了 2.0 的发布说明。上一个 1.x 版本 1.44.2 是 9 月 9 日发的,两者只隔 27 天——但这次跨大版本的间隔本身很长:1.0.0 发布于 2024 年 7 月 1 日,到 1.44.2 走了 800 天、76 个小版本,才等来第一个 2.0。

官方列了五个卖点:初版 out-of-core(落盘)默认开启、大量核心性能改进、SQL 成为一等公民、新增 Map dtype、对 dtype 更严格。最后一条官方给的理由很直白,说更严格能"更快给反馈、更快做 AI 迭代"。

战绩也在:在从 TPC-H 与 TPC-DS 派生的数据上,Polars SQL 与最新的 DuckDB 1.5.6、DuckDB 2.0 alpha、DataFusion 54.0.0 同台跑,默认配置在 8 组对比里赢了 6 组。

先说清口径:这是 Polars 官方自测的基准。官方脚注原话承认结果"无法与已发表的 TPC-H / TPC-DS 基准结果相比",因为不满足 TPC 的合规要求。基准仓库公开在 github.com/pola-rs/polars-2.0-benchmark,官方鼓励别人来复现或反驳。

但这次发布里真正值得写的,不是赢了几组,而是那句话本身:数据放不下的时候,它不再直接崩,而是变慢。

把这件事推到底,是在一台 10 核 macOS 机器上做的一组实验。取一份 800 万行、33.7MB 的 Parquet,只做一次双列排序,然后把可用预算从"随便用"一路压到 8MB:

内存预算

查询耗时

累计写盘块数

是默认的几倍

默认不限

0.515 秒

0 块

1.0

压到 256MB

1.189 秒

2633 块

2.3 倍

压到 32MB

2.478 秒

4644 块

4.8 倍

压到 8MB

2.412 秒

5414 块

4.7 倍

8MB 预算下,它往磁盘写了五千多块、每块写完再捞回来接着算,查询最终还是返回了正确的三行结果。默认配置只要 0.515 秒、一次盘都不碰;压到 8MB 之后是 2.412 秒,慢了 4.7 倍,但没有失败。同一台机器重复三轮,8MB 那一档的写盘块数在 4620 到 5414 之间波动,耗时稳定在 2.2 秒上下。

这就是 2.0 的分水岭:它在"崩掉"和"慢一点"之间选了后者。

顺带一个体积上的反差。从 PyPI 下载的主包 polars-2.0.0-py3-none-any.whl 只有 0.84MB,是个纯 Python 外壳;引擎在另一个依赖包里,macOS arm64 平台那份 45.71MB,解开后的 _polars_runtime.abi3.so 实测 158.0MB。装完落地一共 166.1MB,是主包的 197.7 倍。

Polars 是 MIT 许可、完全免费的开源项目,源码在 github.com/pola-rs/polars,到 2026 年 10 月 7 日有 39957 个 star、3155 个 fork,主语言 Rust,仓库 2020 年 5 月 13 日建。

二、落盘这件事,官方给了十几个旋钮触发线是 80%,磁盘预算是 64GB

官方给的两个数字很具体:内存用到大约 80% 开始往外写,默认磁盘预算是 64GB。目前支持落盘的算子只有排序、窗口函数和很多表达式,join 和 group-by 官方明确说还在路上。

这句话要划重点。最吃内存的两类操作——大表关联和分组聚合——恰好还没进落盘名单。所以"数据放不下也能算"这句话,现在只对一半场景成立。

从 158MB 的那个二进制里,能直接抠出这套机制的完整开关表:

环境变量

作用

POLARS_OOC_MEMORY_BUDGET_MB

内存预算绝对值

POLARS_OOC_MEMORY_BUDGET_FRACTION

内存预算比例,默认 0.8 那条线

POLARS_OOC_DISK_BUDGET_MB

磁盘预算,默认 64GB

POLARS_OOC_SPILL_MIN_BYTES

多大的数据才值得写盘

POLARS_OOC_SPILL_FORMAT

落盘格式,目前只认 ipc

POLARS_OOC_SPILL_COMPRESSION_LEVEL

落盘压缩级别

POLARS_OOC_MAX_PARALLEL_SPILL_TASKS

并发写盘任务数

POLARS_OOC_MEMORY_PREFETCH_FRACTION

提前回捞的触发比例

POLARS_OOC_LOG_METRICS

打印落盘统计日志

POLARS_OOMKILL_THRESHOLD_MB

内存杀进程阈值

POLARS_OVERRIDE_TOTAL_MEMORY_MB

手动声明总内存

十一个旋钮拧一个功能,说明它不是"能用"级别的实现。二进制里的源码路径也印证了这一点:crates/polars-ooc/src/ 下面有 memory_manager.rs、spill_file.rs、spill_frame.rs、spill_token.rs,还有 spill_context/mod.rs 与 spill_context/stats.rs,另有一个专门清垃圾的后台线程 polars-ooc-cleaner。它是个独立的 crate,不是一个函数。

复现上面那张表只要改一个环境变量:

POLARS_OOC_MEMORY_BUDGET_MB=8 \POLARS_OOC_SPILL_MIN_BYTES=1 \POLARS_OOC_LOG_METRICS=1 \python -c "import polars as plpl.scan_parquet('data.parquet').sort(['h','g']).select(pl.col('tag').head(3), pl.len().alias('n')).collect()
日志里那个累计值不能直接读

把 POLARS_OOC_LOG_METRICS 打开,每轮落盘会打一行统计。8MB 那一档的原始输出是:

spill_stats(sort): relief_mb_s(201.92), io(spill=2.37s, unspill=0.00ns),spill(succ=100.0%, n=89), spill_explore(succ=1.5%, n=5847)spill_stats(sort-partition): io(spill=2.15s), spill(succ=100.0%, n=5198)spill_stats(multiplexer): io(spill=303.51ms), spill(succ=100.0%, n=127)

三个阶段的写盘块数分别是 89、5198、127,合计 5414。两个数字值得盯:succ=100.0% 是真正落盘的成功率;spill_explore 是"评估后判断不划算、又放弃"的比例——调度器每试四次,只有一次真的写盘。

这里有个容易读错的地方:三个阶段写盘 I/O 加起来是 4.82 秒,而整个查询墙钟只有 2.412 秒。不是数据错了——io 那一项是各线程的累加值,写盘本身是多线程并行的。日志里的 io 是总工作量,不是你坐在那儿等的时间。

还有一条边界:把磁盘预算改成 256MB,查询会直接报错——

RuntimeError: BindingsError: "query aborted, raise POLARS_OOC_DISK_BUDGET_MB"

也就是说 64GB 默认值是第二道防线。第一道是内存,第二道是磁盘,两道都用完才认输。压得越狠写盘次数也不是单调上升:8MB 那档写了 5414 块,反而比 32MB 那档的 4644 块更多——预算越小,单次写的块越小、越频繁。

三、SQL 成一等公民:30 条语法过了 26 条

"把 SQL 当一等公民"是这次喊得最响的一句。官方说要让同一个引擎接更多工作负载,为此在优化器上补了三样东西:join 重排序、更好的公共子计划消除、动态谓词与布隆过滤器。

覆盖度提升需要验证,所以直接拿 30 条常用语法去打:

结果

语法

通过(26 条)

WITH 公用表表达式、ROW_NUMBER 窗口函数、SUM OVER、QUALIFY 过滤窗口结果、GROUP BY ROLLUP、GROUP BY CUBE、GROUPING SETS、CASE WHEN、LEFT JOIN、UNION ALL、INTERSECT、EXCEPT、DISTINCT、HAVING、LIKE、IN 子查询、标量子查询、EXISTS 子查询、EXTRACT 日期函数、字符串拼接、LIMIT 与 OFFSET、CAST 到 DECIMAL、STRING_AGG、CREATE TABLE AS、DROP TABLE、SHOW TABLES

不支持(4 条)

BOOL_AND 聚合、INSERT INTO 已有表、DESCRIBE、PIVOT

四条的报错各不相同,恰好画出边界。BOOL_AND 报的是 unsupported function 'bool_and',函数没实现;INSERT INTO 报 statement type is not supported,语句类型没认;DESCRIBE 同样报语句类型不支持,但错误里保留了 hive_format 这类字段,说明解析器认得、执行器没接;PIVOT 报得最直白,not yet implemented。

这里有个细节值得留意:CREATE TABLE AS 能跑通,INSERT INTO 不行。意味着它现在的 SQL 是"读"这一侧的一等公民,还不是"写"这一侧的一等公民——你可以用 SQL 描述查询,但还不能用它维护一张有状态的表。当查询语言用没问题,当数据库用会撞墙。

跑通一条带 HAVING 的聚合是这样的:

import polars as plctx = pl.SQLContext(a=df, eager=True)ctx.execute("SELECT dept, sum(amt) s FROM a GROUP BY dept HAVING sum(amt)>30")
四、赢 6 组输 2 组,输的那 2 组更有信息量

官方附录里的原始数据,单位秒,越小越好:

机器

规模与基准

Polars

Polars 32线程

DuckDB 1.5.6

DuckDB 2.0 alpha

DataFusion

16 核 / 32GB

SF10 TPC-H

3.22

4.44

4.27

7.41

16 核 / 32GB

SF10 TPC-DS

16 核 / 32GB

SF100 TPC-H

16 核 / 32GB

SF100 TPC-DS

192 核 / 384GB

SF10 TPC-H

3.10

1.97

2.46

3.12

7.10

192 核 / 384GB

SF10 TPC-DS

9.63

192 核 / 384GB

SF100 TPC-H

9.85

192 核 / 384GB

SF100 TPC-DS

一行行核排名,会得到和"赢了 6 组"不一样的信息:默认配置输掉的两组,全出在同一台 192 核机器的小数据上。SF10 TPC-H 里 DuckDB 1.5.6 用 2.46 秒,Polars 要 3.10 秒;SF10 TPC-DS 里 Polars 的 32 线程版本只要 9.63 秒,默认的 192 线程版本却要 23.16 秒,差了 2.4 倍。

官方自己也认了,原话大意是默认配置在 192 线程时有一份固定开销、小数据查询会吃亏,限制到 32 核以后在所有基准里都能打平或领先,原因已定位、希望下个版本修掉。限制线程数反而更快,这不是黑料,是并行化的常识:数据量不够大时,线程间的同步成本超过并行带来的收益。

另一组数字是扩展性。从 16 核换到 192 核、数据放大到 SF100,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 倍。加机器的收益,Polars 确实是最大的,这一条比那 45% 的领先更能说明引擎结构。

还有一处口径与实现的落差

官方说流式引擎改成默认之后,join、group_by、unpivot 这几类操作不再保证行序,需要行序就设 maintain_order=True。挨个查签名:join 有 maintain_order,group_by 有 maintain_order,unpivot 没有这个参数,传进去直接报 TypeError: unexpected keyword argument。也就是说 unpivot 的行序目前没有开关可拧,只能自己在外面再排一次。发布说明里那句话,对 unpivot 是不成立的。

五、升级的代价落在老代码上

2.0 是跨大版本,代价具体到数字:源码里标记 removed_in="2.0" 的参数共 110 处,其中 58 处直接移除、52 处改名。挨个跑一遍旧写法,报错长这样:

ArgumentRemovedError: the argument 'streaming' for 'LazyFrame.collect'was deprecated in version 1.25.0 and has been removed in version 2.0.Use `engine="streaming"` instead.ArgumentRemovedError: the argument 'join_nulls' for 'LazyFrame.join'was deprecated in version 1.24 and has been removed in version 2.0.It was renamed to 'nulls_equal'.

高频改名集中在几组:min_periods 改叫 min_samples,descending 改叫 reverse,by 改叫 group_by,join_nulls 改叫 nulls_equal,future 改叫 compat_level,columns 改叫 on,dtypes 改叫 schema_overrides。这些报错是严格策略的另一面:它不只在新功能上严格,也在老接口上严格。

谁该升,谁可以不急

该升的三种人。第一种,数据量卡在内存边界上的人——落盘解决的是"跑到 90% 突然 OOM"这类最难受的失败,它不是让查询变快,是让查询有结果。第二种,只想写 SQL 的人——26/30 的语法覆盖加上优化器补的三块,能接住大部分分析型查询,但记住 INSERT INTO 还没有。第三种,用 AI 写查询的人——collect_schema() 能在真正读数据之前把类型和列名解析一遍,实测拿一个引用了不存在列的计划去调,直接抛 ColumnNotFoundError,连数据都不碰;AI 生成的错误查询会在编译阶段被拦下,不用等跑完二十分钟才发现列名写错。

可以不急的三种人。数据量离内存还远的人,那 64GB 磁盘预算和 80% 触发线对你没有意义;还在 Pandas 上的人,这次升级不解决迁移问题;以及生产代码依赖行序的人——你需要的不是升级,是先给那几个 join 和 group_by 补上 maintain_order。

升级前要做的三件事。把 collect(streaming=...) 这类旧写法全局搜一遍换成 engine="streaming";把上面那七组改名逐个扫一遍;把落盘目录挂到一块不跟系统盘抢带宽的盘上,64GB 预算配机械盘会很难看。

六、互动话题

这次发布最有价值的不是那 6 组领先,而是两个反常识:把线程从 192 限制到 32 反而更快,以及数据放不下时选择慢下来而不是崩掉。

一个引擎成熟与否,不看它最快的时候有多快,看它最难受的时候会不会把活交出来。

如果你是做数据分析的,更愿意要一个跑得飞快但遇到大数据就崩的库,还是一个慢一点、但总能给你结果返回的库?评论区说说你踩过的 OOM。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
仅3年!张本智和态度发生180度转变:开心回到成都 数次挑衅中国

仅3年!张本智和态度发生180度转变:开心回到成都 数次挑衅中国

念洲
2026-10-08 14:33:51
兵败如山倒!国产新能源或已证明:中国其实不需要二线豪华品牌

兵败如山倒!国产新能源或已证明:中国其实不需要二线豪华品牌

铭记历史呀
2026-09-20 16:15:46
北大化学才女李天乐,利用职务之便,将清华毕业的丈夫,一点点“熬”死在病房!她领出的剧毒为何消失了?

北大化学才女李天乐,利用职务之便,将清华毕业的丈夫,一点点“熬”死在病房!她领出的剧毒为何消失了?

史源观点
2026-09-29 19:09:22
魏某平(男,32岁)在一小区坠楼,救治无效死亡,官方公布调查结果

魏某平(男,32岁)在一小区坠楼,救治无效死亡,官方公布调查结果

南方都市报
2026-10-08 21:52:05
Mate90首销遇冷:暴跌10万台,涨价2000元后,用户不愿买单

Mate90首销遇冷:暴跌10万台,涨价2000元后,用户不愿买单

叮当当科技
2026-10-09 01:18:22
曝俄军阵亡抚恤金被大幅削减!有的甚至被直接取消

曝俄军阵亡抚恤金被大幅削减!有的甚至被直接取消

项鹏飞
2026-10-07 20:23:33
中国学者得不了诺贝尔奖的根本原因是:诺贝尔奖含“金”量太低

中国学者得不了诺贝尔奖的根本原因是:诺贝尔奖含“金”量太低

必记本
2026-10-06 17:31:43
尴尬了!原定26桌婚宴突来36桌:山东新娘学生家长全家赴宴,10桌缺口让主家酒店总管,集体懵圈

尴尬了!原定26桌婚宴突来36桌:山东新娘学生家长全家赴宴,10桌缺口让主家酒店总管,集体懵圈

火山詩话
2026-10-06 08:31:34
短短一年炎症变癌症?提醒:患上这5种炎症,千万别拖

短短一年炎症变癌症?提醒:患上这5种炎症,千万别拖

芹姐说生活
2026-10-07 22:43:11
湖北省随州市人大常委会党组成员汪海涛接受审查调查

湖北省随州市人大常委会党组成员汪海涛接受审查调查

界面新闻
2026-10-08 20:45:58
尊界汽车发布声明:将进一步优化制动踏板 为已交付用户提供免费升级选择

尊界汽车发布声明:将进一步优化制动踏板 为已交付用户提供免费升级选择

快科技
2026-10-08 21:22:08
国庆假期,7人醉驾被商丘警方查处

国庆假期,7人醉驾被商丘警方查处

天命生商
2026-10-07 08:58:43
“牡丹花下死,做鬼也风流”!这一次,75岁的张纪中彻底成了笑话

“牡丹花下死,做鬼也风流”!这一次,75岁的张纪中彻底成了笑话

妙知
2026-07-12 04:40:34
演员彭玉,在珠海离世

演员彭玉,在珠海离世

南方都市报
2026-10-08 10:24:22
米体:皮奥-埃斯波西托身价飙升,但国米无意放人

米体:皮奥-埃斯波西托身价飙升,但国米无意放人

懂球帝
2026-10-08 14:30:10
再过5年农村基本定型,空心村慢慢退场,村里常住就剩下这三类人

再过5年农村基本定型,空心村慢慢退场,村里常住就剩下这三类人

笑熬浆糊111
2026-10-08 10:31:17
图书馆里这位阿姨的打扮,让她看起来宛如少女,完全看不出多少岁

图书馆里这位阿姨的打扮,让她看起来宛如少女,完全看不出多少岁

美女穿搭分享
2026-10-08 11:11:53
WTT中国大满贯|国乒女队双打同样强势,女双四强揽三席,但男双仅剩一对

WTT中国大满贯|国乒女队双打同样强势,女双四强揽三席,但男双仅剩一对

文汇报
2026-10-09 04:05:14
“别碰我”!28岁美女特警火爆全网:国家级运动员 短跑跳远都很强

“别碰我”!28岁美女特警火爆全网:国家级运动员 短跑跳远都很强

念洲
2026-10-08 14:34:30
社评:蔡英文窜美,是彻头彻尾的卖台

社评:蔡英文窜美,是彻头彻尾的卖台

环球网资讯
2026-10-08 23:13:06
2026-10-09 06:36:49
呼呼历史论
呼呼历史论
分享有趣的历史
645文章数 18370关注度
往期回顾 全部

科技要闻

江淮汽车回应"尊界V800刹车踏板支架断裂"

头条要闻

女局长被举报婚内出轨至少9人 大量亲密聊天记录公布

头条要闻

女局长被举报婚内出轨至少9人 大量亲密聊天记录公布

体育要闻

30天30队·鹈鹕:胖虎又一年“如果”

娱乐要闻

演员王晓慧刚担女主,就被曝已婚生子

财经要闻

央行:中国从不搞竞争性货币贬值

汽车要闻

特别版配色/碳纤尾翼 2027款深蓝L06将于10月9日上市

态度原创

房产
家居
手机
艺术
公开课

房产要闻

三亚崖州,拟出安居房新政!

家居要闻

2026建博会(广州) 公装联探展交流活动

手机要闻

内存涨价压垮利润!三星手机计划Q4减产高达30%

艺术要闻

炸裂!龙门石窟首次发现造像琉璃眼珠,千年佛像竟“睁眼”了,熠熠闪光品相逆天!

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版