当前位置:
AIGC文章详情

同一份 2.3GB 数据:Pandas 跑崩、Polars 花 8.7 秒、DuckDB 只要 12 毫秒——但它们不是三选一,而是流水线上的三个工位

源自35位全网作者

08-25 14:48

最近数据圈一篇实测把不少人看沉默了:同一份 2.3GB、约 120 万行的 CSV,在一台每月 40 美元、4 核 8GB 内存的普通服务器上,跑完全相同的一套操作——读取、筛选、分组聚合、连接一张 5 万行的维表、再排序。结果是这样的:Pandas 内存一路冲到 7.2GB,直接被系统的 OOM killer 干掉,任务崩了;Polars 用 8.7 秒跑完整条流程,内存峰值 1.8GB;而 DuckDB 只花了 12 毫秒,内存峰值 0.4GB。知乎12 毫秒不是打错了,是真的毫秒级。作者反复跑了三次,11ms、13ms,还专门回头检查代码,生怕自己是误查了一张空表。用他的原话说,这个速度“快得令人难堪”。

于是评论区又响起了熟悉的争吵:DuckDB 是不是要干掉 Pandas?Polars 是不是 DuckDB 的平替?我把最近这一周的几篇讨论连着看完了,想先泼一盆冷水——这个问题本身就问错了。它们仨压根不是站在同一条赛道上互相替代,而是同一条数据处理流水线上的三个工位。看懂分工,比纠结“到底选谁”重要得多,因为这直接决定了你花时间学新工具会不会白学。

先给三个工位分个工。最近一位刚给电商客户搭完数据管道的作者有个说法很到位:Parquet 管存、DuckDB 管查、Polars 管转。他把这三件事比作一家小饭馆的仓库、点单台和后厨。知乎Parquet 是仓库。它是列式存储格式,user_id 一列、amount 一列、timestamp 一列,各归各放。你只要三列,它就只读三列,不会像 CSV 那样为了拿几个字段把整行都搬进来。一句话:用多少,读多少。

DuckDB 是点单台。它是个进程内的分析型数据库,import duckdb 就能用,不用起服务、不用连接串、不用先建表。它最擅长的,就是直接对着 Parquet、CSV 这类文件写 SQL。知乎注意,是“直接查文件”,不是“先把文件读成 DataFrame 再查”。数据不用整个塞进内存,算到超出内存时还会自动溢写到磁盘。那 12 毫秒,就是这么来的。

同一份 2.3GB 数据:Pandas 跑崩、Polars 花 8.7 秒、DuckDB 只要 12 毫秒——但它们不是三选一,而是流水线上的三个工位

Polars 和 Pandas 是后厨。类型转换、日期解析、按用户聚合这类清洗和转换的脏活归它们干。Polars 用表达式风格写,底层并行处理,比手写 for 循环快得多。

所以记忆点就一句话:存归存、查归查、转归转。很多人以前图省事,什么都往 Pandas + CSV 里塞,结果文件越攒越大、查询越来越慢——本质上是把三个工位的活,全压给了后厨一个人。

再回头说那组悬殊的数字,差距为什么能拉到这种程度?根源在三者的干活方式完全不同。Pandas 的问题是把所有东西都读进内存,每一行每一列、连每个字符串都作为 Python 对象存着,单个字符串还带着 49 字节的开销;一个 2.3GB 的 CSV 进来,早就不是 2.3GB 了,整数列只要混进一个缺失值整列就变 float64。这次测试里,光是读文件就花了 47 秒。而 Polars 用 Rust 写、走 Apache Arrow 列式格式、默认多线程,还带惰性求值——先构建查询计划,做过滤下推、剔掉用不到的列,再真正执行。DuckDB 则是个查询引擎而非 DataFrame 库,SQL 会编译成优化过的执行计划,底层向量化执行,只读需要的列。顺带一提那份常被引用的 TPC-H 测试:DuckDB 在单台机器上 1 分 16 秒跑完全程,而 Apache Spark 用 32 台机器的集群要跑约 8 分钟,哪怕扩到 1024 个核心也没追上单机 DuckDB。知乎

同一份 2.3GB 数据:Pandas 跑崩、Polars 花 8.7 秒、DuckDB 只要 12 毫秒——但它们不是三选一,而是流水线上的三个工位

那么落到“我到底该用哪个”,可以按数据量分三层来选。

数据能轻松装进内存、加载后不到 1GB:继续用 Pandas。它的生态最成熟,scikit-learn、matplotlib、seaborn、还有数不清的教程都围着它转,做探索性分析它仍是首选;团队都熟、换工具学习成本不划算时,更没必要硬换。

数据变大但还能进内存、大概 1GB 到 100GB:上 Polars。知乎多线程、惰性求值、查询优化、内存效率都是它的强项,适合生产环境的 ETL 管道。代价是语法要重新适应——原来 df[‘column’].mean() 得写成 pl.col(‘column’).mean(),存在学习曲线。

数据大到超过内存,或者你本来就偏爱写 SQL:用 DuckDB。它擅长核外处理、直接查文件、跑以分析为主的负载。但它是 SQL 优先,如果一看到 SQL 就头疼,用起来不会轻松;遇到“用代码比用 SQL 更好表达”的复杂转换,Polars 反而更顺手。

其实多数团队最后都不是三选一,而是混着用:DuckDB 负责数据摄取和重活 SQL 分析,Polars 承担复杂转换和特征工程,Pandas 留给最后一公里的机器学习、可视化和出报告。三者各司其职,谁也不抢谁的饭碗。

同一份 2.3GB 数据:Pandas 跑崩、Polars 花 8.7 秒、DuckDB 只要 12 毫秒——但它们不是三选一,而是流水线上的三个工位

几个坑提前说在前面。第一,别拿 DuckDB 的 12 毫秒去踩 Pandas——它俩优化的根本不是一个环节,一个是查、一个是全流程读进内存算,场景不同没法直接比高低。第二,Polars 的生态确实还小,scikit-learn 目前还不能原生接收 Polars 的 DataFrame,如果你的下游全是 sklearn,得先想好衔接。知乎第三,DuckDB 快的前提是“分析型”负载,如果你要的是大量逐行转换,那它是查得快、转得未必顺手。

往后值得继续盯两个信号。一个是 DuckDB 的生态扩展还在快速补,直接查文件、打通各种数据格式的路子越来越宽。知乎另一个是 Polars 能不能把生态短板补齐。这两个变量会直接影响上面那套选型建议的保质期。

说到底值不值得换?我的判断是:不用恐慌式迁移,但也别装看不见了。数据还在 1GB 以内、跑得动,Pandas 照用无妨;可一旦你开始被“内存爆了、跑得太慢、文件太大”这类问题反复折磨,这套“Parquet 存、DuckDB 查、Polars 转”的分工,就是目前单机上性价比最高的一条出路——它替你把“上云、上集群”这笔大钱,省成了本地几行代码的事。

同一份 2.3GB 数据:Pandas 跑崩、Polars 花 8.7 秒、DuckDB 只要 12 毫秒——但它们不是三选一,而是流水线上的三个工位

内容由AI生成
0
扫一下,分享更方便,购买更轻松
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

最新文章 热门文章