alitrack

多个 agent 抢一个 DuckDB,官方给了三条路

DuckDB 并发的三条路

DuckDB 并发的三条路

最近一个说法在网上被重复得挺多:「DuckDB 是单进程数据库,一个库一次只允许一个连接。」

这句话的后半句是错的。而且错得挺关键——它会让你在设计多 agent 并行的时候,直接得出「DuckDB 不能并行,只能排队」的结论。

我去把官方文档的并发那一页从头到尾读了一遍。原文写得比这句流传的话细得多,而且给出的路数不止一条。

● ● ●

官方文档到底怎么写的

DuckDB 官方文档把并发分成三块讲,我逐条抄一下要点:

第一,单个进程内。 读写模式下,一个进程可以同时读写,而且支持多个写线程——靠 MVCC 加乐观并发控制来保证一致,但所有写都收在那一个进程里。也就是说「连接」从来不只一个,进程里开多连接是它的正常形态。

第二,只读模式。 官方原文写得很清楚:只读打开时,多个进程可以同时读同一个库,只是谁都不能写。

第三,多个进程写。 这才是那个「一个」真正指的东西——同一时刻只有一个进程能持有写权限。官方给了两条出口:一是走 Quack 远程协议,把 DuckDB 变成 client-server 架构(2026 年 5 月 12 日发布,默认端口 9494,起服务用 quack_serve(),查询用 quack_query(),或者直接 ATTACH 'quack:host');二是 DuckLake 格式 + PostgreSQL 做 catalog,官方把它标成「稳定方案」,DuckLake 1.0 规范是 2026 年 4 月发布的。

Quack 现在还是 beta(v1.5.2 起进入 beta),官方预计到 DuckDB v2.0、也就是 2026 年秋天成熟。

● ● ●

这句话为什么不能错

因为它改变的是架构决策,不是措辞。

如果你信「一个连接」,那多 agent 并行就只剩一个答案:串行排队。但官方已经给的三条路里,第二条今天就能用(只读多进程),第三条正在成熟(Quack)。

有意思的是,那篇被转得挺多的英文工作流文章里,讲多窗口操作的时候提到过一句「DuckDB 发布 Quack 服务器时」——那篇文章的场景起点,正是 Quack 发布这件事。但后面列「多个 agent 并行怎么办」清单的时候,Quack 没出现。

● ● ●

三条路,按场景挑

你的场景
走哪条
一个进程里多个线程读写
原生支持,什么都不用做(MVCC + 多写线程)
多个 agent 只读同一份数据
用只读模式打开,多进程并发读,没有锁
多个 agent 都要写
Quack(beta)或 DuckLake + PostgreSQL catalog(稳定)
只想不抢锁,不在乎事务
用 Parquet/CSV 文件当交换层,各写各的

最后一行看起来最土,但在「一次性的探索分析」里它其实是最省事的答案——文件本身没有锁,谁也不用等谁。这也正是那篇文章给的方案,它和官方建议的方向一致,只是他给的理由说错了。

● ● ●

我自己的选法

如果是读多写少(比如几个 agent 分别查不同的表、各写各的结论),我只做一件事:只读打开。一个参数,多进程并发,代价是零。

如果是真的要并行写同一份数据,那我会走 DuckLake + PostgreSQL,不去赌 beta 通道。理由很简单:写路径出错的时候,你分不清是自己的 SQL 错了还是通道在抖。

如果只是一次性 EDA,我就干脆一人一份 Parquet——没有锁、没有事务、没有排队,最后合并的时候再想办法。

顺带一句,如果你在给 agent 写上下文文件(那种项目里放着的、规定它「用哪个工具、连哪个库」的说明文件),有一句话的写法值得改:

  • 别写:「DuckDB 一次只支持一个连接。」——模型会按这个去设计排队。
  • 写:「同一个 DuckDB 库文件,同一时间只能有一个进程写;读可以多进程并发。」——它才会去找只读、Quack 或者 DuckLake 这些路。

● ● ●

留一个问题

官方说 Quack 到 v2.0 成熟。真到那天,「单机 DuckDB」和「DuckDB 服务器」之间的界线会变得很模糊——我更好奇的是,到那时候还会不会有那么多人把 DuckDB 当成一个「进程内的库」来用。

如果你手上正好有多 agent 抢库的经验,欢迎说说你最后选的是哪条路。


参考来源:DuckDB 官方文档 Concurrency 页(docs/current/connect/concurrency.md)、Quack Remote Protocol 页、DuckLake 官方文档 connecting 页。文中数字与原文口径一致,均为官方文档原文。