把单机分析引擎直接挂上云端对象存储,一直是近几年数据工程里最流行的偷懒办法。很多人指望 DuckDB 2.0 的架构翻新能把远程读取卡顿一并解决,但最新的实测数据迅速给这种预期划出了一条明确的物理红线:大文件能提速三倍,碎文件提速近乎为零。

DuckDB 2.0 正式版定于 2026 年 10 月 21 日发布,官方在 9 月 2 日放出的预览版明确标注了非生产就绪。虽然 MotherDuck 博文以 1.5.5 为对照基准,但此时稳定的 1.5.6 已经上线。撇开版本迭代的微小落差,这次 2.0 最核心的变化只有两个:异步 I/O 解耦了下载与解包计算,重写的递归公共表表达式(CTE)重构了迭代探测机制。

这两项改进切中了过去单机跑远程分析的两大痛点,但每一项提速背后都有严苛的前提条件。

线程池解耦:从交替发呆到打满带宽

在过去 1.5.x 时代,每个 Worker 线程既要干体力活又要干脑力活。它先发起网络请求把数据块拖回来,等待期间 CPU 核心只能闲置;等数据到手开始解包和聚合时,网络通道又处于停滞状态。

2.0 把这两件事彻底拆开。独立的下载线程池专门负责从 AWS S3 预取 Row Group 填入内存缓冲,计算线程只管从缓冲区取数解码。两件事在时间轴上重叠,直接消除了交替空转的等待成本。

DuckDB I/O 架构演进:从串行等待到流水线重叠 DuckDB 1.5.5:单线程交替执行 网络下载 (I/O) CPU 空转等待 网络闲置停滞 解包计算 (CPU) 缺点:CPU 与网络交替闲置,吞吐受限 DuckDB 2.0:解耦流水线作业 专用线程池持续预取 (I/O) Worker 线程并行解包 (CPU) 收益:读写并发重叠,打满硬件吞吐

在家庭宽带直连 S3 us-east-1 的环境里,扫描一个 2.2GB、包含 2268 个 Row Group 的 Parquet 文件单列,耗时从 18.8 秒降至 7.7 秒;扫描 23 个共 13.6GB 的大型文件,耗时从 11.8 秒降至 3.9 秒;即便处理 1.7GB 的纯文本 CSV,耗时也从 116 秒压缩到了 55 秒。

在云端无网络抖动的同地域极限环境下,这种解耦的威力更加凶猛。官方 7 月在 64 核心、512GB 内存的 EC2 实例上压测 TPC-H Q6 SF100,扫描约 22GB 的单文件耗时从 8.230 秒降至 2.844 秒,提升达 2.9 倍;976 个约 22MB 的文件耗时也从 9.344 秒降至 2.945 秒。如果激进调整连接参数,扫描耗时能压到 2.227 秒,几乎榨干了主机 25 Gbit/s 的物理网络带宽。

但这里存在一个关键的机制认知偏差。原作者推测控制预取深度的参数由 CPU 线程数静态计算,官方技术文档则表明该默认值完全由可用内存动态治理。预取任务必须与系统的哈希连接、排序以及窗口函数共享全局内存预算。当系统内存承压时,预取池会自动降级收缩为单个任务,并不存在无上限的提前拉取。

此外,异步 I/O 的范围目前仅覆盖 Parquet 与无压缩、支持 Seek 的 UTF-8 CSV 格式,其他文件格式并不能无缝享受到流水线收益。

碎文件陷阱:架构翻新越不过网络时延

吞吐量能靠流水线翻倍,但往返延迟不能。

当把测试对象换成 30 个约 1MB 的细碎 Parquet 文件时,性能提升瞬间停滞:1.5.5 耗时 3.7 秒,2.0 耗时 3.3 秒,耗时几乎完全重叠。

场景规格与文件分布1.5.5 耗时2.0 alpha 耗时加速倍数与现象
1 个 2.2GB Parquet(读单列)18.8 秒7.7 秒2.4x(预取跑满吞吐)
23 个大 Parquet(共 13.6GB)11.8 秒3.9 秒3.0x(多文件流水线重叠)
1 个 1.7GB 无压缩 CSV116 秒55 秒2.1x(顺序 Seek 提速)
30 个约 1MB 碎片 Parquet3.7 秒3.3 秒1.1x(被网络往返阻塞)

Parquet 格式有固定的物理约束。客户端要读取一个文件,必须先发起网络往返请求拿到文件末尾的 Footer 元数据,解析出 Schema 与数据块偏移量,然后再发起第二次请求读取实际的数据列。

这意味着每个文件至少需要两次网络往返时延(RTT)。面对 30 个文件,即便把并发预取开到极限,物理世界里来回握手通信的基础延迟也无法被抹掉。在几百毫秒的往返耗时面前,下载几十 KB 元数据和解码几兆字节的计算开销根本微不足道。

  • 提醒.引擎层面的预取优化无法替代存储治理,大量碎片小文件依然是数据湖查询的死敌。

40 倍跃升:图遍历不再重复建表

除了 I/O 管道,另一个重构落在了递归 CTE 引擎上。

以往用 SQL 处理员工层级汇报、Git 提交历史或物料清单这类具有深度父子关系的数据,性能极易失控。1.5.5 在面对递归查询时,每向下走一层深度,就会机械地把整张父表从头到尾重扫一遍。八层的组织架构意味着全表扫描八次,成千上万层的提交链则会导致海量的重复扫描与建表调度开销。

递归 CTE 核心指标:100 万条边可达性基准测试 DuckDB 1.5.5 中位耗时 4.051s 机制:每轮迭代全表重扫 DuckDB 2.0 中位耗时 0.095s 机制:哈希表常驻探测 基准性能提升幅度 42.6x 测试:10 万节点可达遍历

随着 PR #22211 与 PR #24031 的合并,2.0 彻底重写了执行机制。新引擎在初次读取父表后,直接在内存中建立关于连接键的全局 Hash Table,并在后续多轮迭代中全程保留。每一轮循环只需拿上一轮发现的新增节点去哈希表里做点查,计算代价被严格收敛在实际触达的数据行规模上。

官方发布的基准测试显示,在包含 100 万条边、10 万个节点、2 万个可达节点的图遍历测试中,DuckDB 2.0 的中位耗时从 4.051 秒骤降至 0.095 秒,提速达到 42.6 倍。在作者模拟的 2 万次提交的 Git 历史链条回溯中,原本需要 1.8 秒至 16 秒的查询也被压实到了稳定 0.10 秒。

算子的改写把图数据库的私有领地,切下了一块送给标准 SQL。

不过这种数十倍的跳变高度依赖纯内存与特定的合成拓扑。如果在真实业务场景中遇到了分支极多、关系网极度复杂的非树状网格,单节点的内存容量依然是其不可回避的硬约束。

结语:别指望单机引擎替你补课

近期分析引擎领域的竞争明显加速,Polars 在 10 月初发布的 2.0 基准测试里拉上了 DuckDB 1.5.6、2.0 alpha 和 DataFusion 54 展开较量。但那场横评主要基于本地 EBS 磁盘,在复杂的对象存储网络和碎片化场景中,行业内至今缺乏公允的独立评测。

DuckDB 2.0 在单机分析引擎的边界上交出了漂亮的答卷。异步流水线榨干了宽带吞吐,常驻哈希表拆除了递归死循环,新增的 VARIANT 类型与字段打散存储也为半结构化日志分析带来了接近列存的压缩比。

  • 建议.尽早建立文件合并流程,将远程对象存储的单文件尺寸稳定在几十兆至上百兆区间。

软件工程可以重构代码、榨干 CPU、预取数据,但它改变不了光缆里的物理延迟。如果数据湖底层躺着成千上万个 1MB 大小的碎片文件,任何精妙的客户端流水线最终都会在网络往返的叹息墙前败下阵来。