pgrust 让 Postgres 分析查询快 300 倍

数据库圈子最近出现一个令人咋舌的基准成绩:用 Rust 写的 pgrust 项目,在分析型查询上比原生 PostgreSQL 快了约 300 倍,在 ClickHouse 的 ClickBench 基准上甚至跑赢了 ClickHouse 本身。pgrust 作者在一篇技术长文中拆解了这背后最关键的一环——查询引擎,以及三招把它从「慢」救到「快」的优化。

PostgreSQL 诞生于磁盘 I/O 是主要瓶颈的年代,而如今很多数据集能直接塞进内存,分析负载的瓶颈早变成了 CPU 和内存带宽。pgrust 的查询引擎单独就贡献了约 10 倍的提速。作者用「求前 5 亿个数的和」这个简单查询来量化差距:同样的活,原生 Postgres 在关掉并行后跑了约 20 秒,而一段朴素的 Rust 循环只要 358 毫秒,快了约 55 倍。

差距的根源在 PostgreSQL 使用的「火山模型」(Volcano model)执行器。它要求每个计划节点都实现一个 next() 方法、一次只返回一行。作者照着这个模型写了个迷你版,耗时 1.3 秒——比原生 Postgres 快,但仍远慢于裸循环,因为每行都调一次函数的开销实在太大。

第一招是批处理。把 next() 改成一次返回 1024 行,绝大多数函数调用开销被抹掉,耗时从 1.3 秒降到约 480 毫秒(2.7 倍)。关键是批处理缓冲区分配在栈上,运行时不再频繁申请内存。

第二招是算子融合。既然顺序扫描和求和总是一前一后出现,就把两个节点合并成一个,省掉中间拷贝,直接回到 358 毫秒(3.6 倍)的裸循环水平。作者坦言这算「作弊」,因为写死了特定查询,但 pgrust 真正的通用解法是 JIT 编译——为每条查询现场生成最优代码,从而对任意查询都能做算子融合。

第三招是 SIMD。在 aarch64 架构上用单指令多数据指令一次处理多行,耗时进一步压到 135 毫秒(9.6 倍),比裸循环还快近 3 倍。代价是浮点加法不满足结合律,求和顺序改变会带来微小误差——这也是编译器默认不敢擅自上 SIMD 的原因。

整套基准跑在 AWS c8g.4xlarge(Graviton4、16 vCPU)上,使用 PostgreSQL 18.4、关闭并行、数据预热进共享缓冲、取 5 次运行的中位数。作者总结,正是批处理、算子融合、SIMD 这些底层优化,让 pgrust 的分析查询达到数百倍于 Postgres 的速度。

来源:malisper.me