DuckDB 2.0 预览版:那只说"不搞分布式"的鸭子,食言了
先说一组让人不太舒服的数据。
2019 年,DuckDB 诞生在荷兰国家数学与计算机科学研究所(CWI),两位创始人给它定的调子是:嵌入式、进程内、不开服务器、不搞分布式。他们甚至在演讲里反复强调一个判断——99% 的用户远远达不到"大数据"的体量,你不需要集群,你只需要一个能跑在你自己进程里的快刀。
六年过去了,这只鸭子的 GitHub Star 数刚在 2026 年 8 月 5 日突破 40,000,PyPI 月下载量 5,000 万+,官网每月独立访客超 800 万,光扩展下载产生的流量就超过 2 PB。
然后 2026 年 8 月 17 日,官方发了一篇 17 分钟长文:《A Preview of DuckDB v2.0》。
代号 Cyanoptera(桂红鸭,一种分布在美洲西部的红褐色鸭子)。距 2026 年 3 月发布的 v1.5,中间堆了 超过 10,000 次提交。而这篇文章的第一条特性是:
DuckDB as a Server。
是的。那只靠"我就是不长服务器"出圈的鸭子,给自己装了个服务器。
我第一反应是笑出了声。第二反应是——这大概是近几年数据库圈最诚实的一次"打脸"。
先把话说清楚:DuckDB 到底是个啥
一句话版本:DuckDB 是一个进程内(in-process)的列式 OLAP 数据库。
官方自己给过一个特别精准的类比:
SQLite : OLTP :: DuckDB : OLAP
它不像 MySQL、PostgreSQL 那样需要你起一个守护进程、开一个端口、配一堆权限。它就是一个库文件,被你的 Python / Go / Java / Node 进程直接加载进去,然后你就拥有了一个能跑完整标准 SQL 的分析引擎。没有网络跳转,没有序列化开销,没有运维。
它的成名技是这句:
SELECT * FROM 's3://bucket/logs/*.parquet' WHERE level = 'ERROR';不用建表,不用入库,不用 ETL,一个 SQL 直接怼到对象存储上。做数据分析的人第一次跑通这条语句时的表情,我见过好几次,基本都是"……就这?"
版本节奏大概是这样的:
| 版本 | 代号 | 时间 | 关键点 |
|---|---|---|---|
| 1.0.0 | SnowDuck | 2024-06 | 首个稳定生产版,存储格式向后兼容 |
| 1.2.0 | Histrionicus | 2025-02 | CSV 读取器重写、扩展 C API |
| 1.3.0 | Ossivalis | 2025-05 | Parquet 读写器重写 |
| 1.4.0 | Andium | 2025-09 | 首个 LTS 版,AES-256 加密、MERGE INTO |
| 1.5.0 | Variegata | 2026-03 | 内置 GEOMETRY、VARIANT 类型、新 CLI |
| 2.0.0 | Cyanoptera | 2026 秋(预览中) | 服务器模式、异步 IO、新存储格式、稳定扩展 ABI |
注意最后一行:v2.0 目前是预览版,正式版定在 2026 年秋季。
2.0 到底改了什么:七个真正值得关心的点
官方文章列了十条,我按"对普通人的冲击程度"重新排了序,讲七个。
1. Quack 协议 + CONNECT:鸭子开起了服务器
这是本次的头号变化。quack 扩展实现了 DuckDB 之间的原生通信协议,在 v2.0 里从预览毕业为稳定。
服务端,一行起服务:
CALL quack_serve(token = 'my_token');客户端,连上去查:
ATTACH 'quack:server.example.com' AS qk (TOKEN 'my_token');
CONNECT qk;
SELECT count(*) FROM events; -- 在服务端执行,结果流式返回
DISCONNECT;更狠的是 CONNECT 不只认 DuckDB。新的远程下推优化器能把 SQL 直接扔给 PostgreSQL 和 MySQL 执行,而不是把整张表拖过网络:
CONNECT 'postgres://localhost/mydb';
SELECT count(*) FROM orders; -- 跑在 PostgreSQL 服务器上
DISCONNECT;DuckDB 从第一天起就是个带完整 MVCC 和事务隔离的事务型数据库,只不过大多数人在单人场景下从没用上过这套 machinery。服务器模式终于让它在多租户、长驻部署里有了用武之地。
配套地,v2.0 重做了 metrics、日志和可观测性子系统——毕竟一个要 7×24 跑着的进程,不能只靠"感觉挺快的"。
有意思的是社区反应:Quack 预览发布才几周,就有人自己写了独立的 Quack 客户端。官方的原话是 "the world said no, no, no, and built their own clients",语气里那点心虚和得意,藏都藏不住。
2. VARIANT:JSON 不用再当字符串供着了
VARIANT 在 v1.5 首次登场,v2.0 里算是彻底长开了。官方的说法是 "JSON on steroids"——打了激素的 JSON。
和普通 JSON 一样,每一行可以长成不同形状;不一样的是它不是文本。DuckDB 会自动嗅出半结构化数据里藏着的公共结构,把它"切碎"(shred)成列式表示,压缩友好、查询飞快,而且你不用声明 schema。
CREATE TABLE events (payload VARIANT);
INSERT INTO events
VALUES ('{"user": {"id": 42, "tags": ["a", "b"]}}'::JSON::VARIANT);
SELECT variant_type(payload), variant_keys(payload) FROM events;
SELECT * FROM events
WHERE variant_contains(payload, {'user': {'id': 42}}::VARIANT);这对日志摄取场景简直是降维打击。日志这玩意儿结构相似但天天在变,以前你要么硬套 schema 天天改表,要么把 JSON 塞进 TEXT 字段然后祈祷查询别太慢。现在不用选了。
官方还埋了个伏笔:未来打算用 VARIANT 支撑常规的 JSON 类型,让现有的 JSON 工作负载不改一行查询就白嫖全部收益。
3. 触发器:审计表不用在应用层写 if 了
这是个被求了很多年的功能,v2.0 一口气给全了:BEFORE/AFTER、FOR EACH ROW/FOR EACH STATEMENT、转换表、同事件多触发器、DROP TRIGGER。
CREATE TRIGGER trg_audit AFTER UPDATE ON target
REFERENCING OLD TABLE AS o NEW TABLE AS n
FOR EACH STATEMENT
INSERT INTO audit
SELECT n.id, o.val, n.val FROM o JOIN n ON o.id = n.id;放在长驻的 DuckDB 服务里,触发器特别合适——终于有个东西能替你在数据库层把"谁改了什么"记下来,而不是靠应用层的自觉。
4. 异步 IO:S3 上的查询终于不憋屈了
和对象存储打交道是 DuckDB 的核心体验,但过去的同步访问把并行度卡死了。v2.0 在整个引擎层面引入异步 IO,让 I/O 层可以独立于查询处理层扩展。
Parquet 先吃上,然后是 CSV 和 DuckDB 自己的文件格式,还加了异步 Parquet 写入和新的 MMAP / DIRECT_IO 模式。
**本地盘也有小幅提升,但真正的巨大提升在网络存储上。**如果你日常是在 S3 / GCS / OSS 上跑分析,这条可能是你体感最明显的一条。
5. 性能:递归 CTE 从 4.90 秒干到 0.12 秒
官方给了个微基准:笔记本上跑一张 100 万条边的图,单源可达性查询,用普通递归 CTE 写。
CREATE TABLE edges AS
SELECT (range % 100_000)::INTEGER AS src,
((range * 13 + 7) % 100_000)::INTEGER AS dst
FROM range(1_000_000);
WITH RECURSIVE reachable(node) AS (
SELECT 0
UNION
SELECT dst FROM edges, reachable WHERE src = node
)
SELECT count(*) FROM reachable;| 版本 | 耗时 |
|---|---|
| DuckDB v1.5.4 | 4.90 s |
| DuckDB v2.0 (preview) | 0.12 s |
**约 40 倍。**同一条 SQL,一个字没改。
其他顺带提速的:部分聚合下推到 join 之下、冗余聚合复用、聚合超内存时溢写磁盘、Windows CLI 多线程结果物化约 2.2×。
行组剪枝也大幅扩了:min-max 索引和 Parquet Bloom filter 现在能为 struct、list、decimal、UUID、IN 过滤甚至函数谓词跳过数据。查询规划还变成分区感知的,对 DuckLake、Iceberg 和 S3 上的 Hive 分区 Parquet 特别有用。
-- 这些现在能剪掉行组,而不是全表扫描
SELECT * FROM logs WHERE contains(message, 'ERROR');
SELECT * FROM t WHERE substr(code, 1, 3) = 'NL-';
SELECT * FROM 'data/*.parquet' WHERE id IN (1, 5, 9);6. 扩展 ABI:一次编译,跨版本通用
这一条对生态的意义,可能比服务器模式还大。
过去 DuckDB 的扩展(包括官方自己的)基本都是对着不稳定的 C++ 内部 API 编的。结果就是:哪怕你的扩展一行代码没改,每个 DuckDB 新版本都得重新构建发布一次,不重建用户就装不上。
v2.0 引入版本化的 C API,规范用 YAML 定义,大部分符号标记为 stable 和 frozen,提供稳定的 ABI。上层再包一层薄的 C++ API,官方还在做 Rust 绑定。
而且组织不再被官方仓库绑死,可以自建、加密固定、自己托管扩展仓库:
SET allow_extension_repositories = 'allowed';
CREATE EXTENSION REPOSITORY my_repo FROM 'https://extensions.example.org';
INSTALL my_ext FROM my_repo;
LOAD my_repo/my_ext;仓库创建时 DuckDB 会拉取公钥并固定下来,打印 SHA-256 指纹,支持多密钥轮换,随时能用 duckdb_extension_repositories() 审计。
对企业来说,这意味着扩展管理终于能纳入自己的基础设施管控范围。
7. 顺手干掉的几件事
- 新的 PEG 解析器:扔掉了从 PostgreSQL 继承来的老解析器。扩展以后能直接挂到语法上,注册自定义 SQL 语法;报错信息也带精确源码位置了。官方说对用户应该无感——如果你感觉到了,去提 issue。
- 删掉 ICU 依赖:时区、日历、排序规则全部自己实现,时区数据直接从 IANA 库构建并压到约 45 kB。附带收益是更快——2500 万行时区转换从 0.24s 降到 0.11s(2.2×),500 万行德语排序过滤从 0.15s 降到 0.06s(2.6×)。
- 存储格式升到 v2.0.0:列元数据延迟加载(宽表打开更快)、
DICT_FSST字符串压缩默认开启、删除操作紧凑存储、ART 索引增量 checkpoint vacuum。代价是这是一次破坏性变更。
谁在用,省了多少钱
讲了半天特性,来点真金白银的。
Spotify 在 DuckCon 上分享过,用 DuckDB 作为用户收听历史之上的 SQL 层。官方 40k Star 博客里专门点了名。
Arcesium(华尔街金融科技)在 2026 年 6 月 30 日的工程博客里写了他们从 Athena 迁到 DuckDB 的 18 个月:数千条生产 SQL、数十个金融客户、复杂的投资组合计算,整体成本砍半。他们也没藏着掖着——Schema 推断会踩坑,S3 连接不显式指定 ENDPOINT 就报 IO Error,有些参数文档里不好找得读源码。作者的结论很实在:这条路不容易,但对金融科技这种查询多变、并发高、不依赖 PB 级扫描的场景,DuckDB 的简洁性和经济性值得这笔迁移成本。
Definite(一家做分析平台的创业公司)把整个栈建在 DuckDB + DuckLake 上,给出的账单对比是这么个画风:
| 组件 | Snowflake + Looker | Definite (DuckDB/DuckLake) |
|---|---|---|
| 计算 | $2,000–5,000/月 | 包含 |
| 存储 | $40–80/月 | $20–40/月 |
| BI 工具 | $1,000–3,000/月 | 包含 |
| 连接器 (Fivetran) | $500–2,000/月 | 包含 |
| 总计 | $3,500–10,000/月 | $250–500/月 |
这不是省 20%,这是差一个数量级。他们的仪表盘典型查询在 200–400ms,而 Snowflake X-Small 需要 2–5 秒。
DuckDB-WASM 那边也有狠活:有团队给某市政府做公开数据可视化看板,浏览器直接读 S3 上的公开 Parquet,全部聚合和渲染都在客户端完成,服务端计算成本为零,100 万用户量级压测通过。
至于 MotherDuck(DuckDB 的商业云服务),2026 年 Q1 付费团队数突破了 10,000。
顺带一提,DuckDB 背后的公司 DuckLabs 明确拒绝过风险投资,理由是"融资会把项目方向推向变现"。项目的知识产权由一个独立非营利组织 DuckDB Foundation 持有,章程保证 DuckDB 以 MIT 协议永久开源。从今年秋季起,基金会还会增设一个利益相关者顾问委员会,给 DuckDB、DuckLake、Quack 的路线图提意见。
初体验:五分钟跑起来
预览版已经在各大平台和语言客户端上放出来了。想尝鲜,Python 用户一条命令:
pip install duckdb --pre验证一下版本:
python -c "import duckdb; print(duckdb.__version__)"CLI 用户去 GitHub Releases 抓对应平台的预览构建,解压即用,和以前一样,双击就跑。
跑个最小闭环体验一下服务器模式,开两个终端:
终端 A(服务端)
duckdb server.duckdbCREATE TABLE events AS SELECT * FROM range(1_000_000) t(id);
CALL quack_serve(token = 'dev_token');终端 B(客户端)
duckdbATTACH 'quack:localhost' AS qk (TOKEN 'dev_token');
CONNECT qk;
SELECT count(*) FROM events;
DISCONNECT;玩一下 VARIANT:
CREATE TABLE logs (payload VARIANT);
INSERT INTO logs VALUES
('{"level":"ERROR","msg":"disk full","host":"a-01"}'::JSON::VARIANT),
('{"level":"INFO","msg":"ok","host":"a-02"}'::JSON::VARIANT);
SELECT variant_extract(payload, '$.level') AS lvl, count(*)
FROM logs GROUP BY lvl;冷静一下:现在该不该上
我个人立场是——玩,别上生产。
理由很具体:
- 这是预览版,官方原文明确说"在秋季发布之前,部分细节可能仍会调整"。
- 存储格式是破坏性变更。v2.0 默认存储格式升到 v2.0.0,老版本创建的库文件需要升级才能用,而且回不去。正式版的发布公告里会把迁移细节讲清楚,在那之前别动你的生产库。
- lambda 语法过渡完成,这也是一处 breaking change。
适合现在动手的三类人:打算贡献扩展的、在做技术选型的、纯粹想看看分析引擎未来长什么样的。剩下的人,等秋天。
不过话说回来,v2.0 传达的信号比它本身更重要。
一款"我就是不搞分布式"的数据库,最终还是长出了服务器、网络协议和下推优化——不是因为它背叛了初衷,而是因为用户规模到了那一步,需求自己会找上门。单二进制的简洁性它还没丢,这已经相当克制了。
进阶
想系统学 DuckDB,可以先看我们的认识DuckDB和玩转DuckDB。想看它在超大规模 CSV 上的表现,玩转超亿级CSV和百亿级数据性能测试里有完整的实测数据。
官方那份 v2.0 预览长文(10 条特性全量细节)和异步 IO、PEG 解析器的专题博客,都值得通读一遍。
更多开源技术干货和学习资料,关注公众号「遇码」,领取专属福利。
