DuckDB v2.0 预览
摘要
本文预览了即将发布的 DuckDB v2.0 功能,包括服务器模式、新的 SQL 解析器和存储格式,标志着数据库系统的重要更新。
<p><a href="https://lobste.rs/s/wya4zt/preview_duckdb_v2_0">评论</a></p>
查看缓存全文
缓存时间: 2026/08/17 18:09
# DuckDB v2.0 新特性预览 来源:https://duckdb.org/2026/08/17/duckdb-20-highlights
*简而言之:DuckDB v2.0 将于今秋发布。本文将预览其主要特性:DuckDB 作为服务器、触发器、VARIANT 类型、异步 I/O、全新 SQL 解析器、新存储格式及更多功能。*
DuckDB v2.0 将被命名为"Cyanoptera"(青翅鸭),其名称来源于肉桂色翅鸭(Cinnamon teal)(https://en.wikipedia.org/wiki/Cinnamon_teal)*(学名:Anas cyanoptera)*——一种在美洲西部常见的、具有显著红褐色羽毛的鸭类。我们对大版本号的升级非常慎重,这绝非形式主义:v2.0 版本带来了全新的 SQL 解析器、新的默认存储格式、重构的 C API 以及少数经过精心挑选的破坏性变更。但更重要的是,自今年三月发布 v1.5 以来,我们基于超过 10,000 次提交打造了这个功能发布版。如果说去年是数据湖仓之年,那么此版本则开启了 DuckDB 作为服务器之年。
如果您更喜欢观看视频而非阅读文字,我们曾在 DuckCon #7(https://www.youtube.com/watch?v=iFPKNQu0FtE)的"DuckDB 现状"演讲中预览了其中许多特性。DuckDB 发展迅速,我们在此只能介绍其中一小部分变更。将所有新特性精简为短列表总是充满取舍——是的,我们知道下面的内容在形式上确实是篇列表文(*《DuckDB v2.0 即将带来的十大特性,第八个让你大吃一惊》*)。我们虽不推崇这种形式,但它确实有效。那么,让我们从 SQL 层特性开始,逐步深入引擎内部。
## 1. DuckDB 作为服务器:`quack` 扩展与 `CONNECT` 语句(https://duckdb.org/2026/08/17/duckdb-20-highlights#1-duckdb-as-a-server-quack-and-connect)
DuckDB 自诞生之日起就是一个进程内数据库。但用户一直(非常执着地)向我们请求客户端/服务器模式,我们最终妥协了。`quack` 扩展(https://github.com/duckdb/duckdb-quack)实现了 DuckDB 与其他 DuckDB 实例通信的原生协议。它在 DuckCon #7 之前作为预览版发布(https://duckdb.org/2026/05/12/quack-remote-protocol.html),在 v2.0 中升级为稳定版。这也是 DuckDB 未来发展方向的重要组成部分:任何 DuckDB 进程都可以通过网络提供其数据库服务,任何其他 DuckDB 可以通过新的 `CONNECT` 语句连接到它并路由查询。
例如:
#### DuckDB 服务端(https://duckdb.org/2026/08/17/duckdb-20-highlights#duckdb-server)
```sql
CALL quack_serve(token = 'my_token');
```
quack:
#### DuckDB 客户端(https://duckdb.org/2026/08/17/duckdb-20-highlights#duckdb-client)
```sql
ATTACH 'quack:server.example.com' AS qk (TOKEN 'my_token');
CONNECT qk;
SELECT count(*) FROM events; -- 在服务器上执行,结果流式返回
DISCONNECT;
```
`CONNECT` 是我们在 Quack 首次亮相时展示的 `remote.query($$...$$)` 变通方法的升级版——我们审视了那个语法后认为:不行,不能这样。而且 `CONNECT` 不仅限于 Quack:它可以将您的会话指向任何支持该协议的远程数据库,新的远程下推优化器(#22914(https://github.com/duckdb/duckdb/pull/22914))可以直接将 SQL 发送到 PostgreSQL 和 MySQL,而不是通过网络拉取整个表:
```sql
CONNECT 'postgres://localhost/mydb';
SELECT count(*) FROM orders; -- 在 PostgreSQL 服务器上运行
DISCONNECT;
```
如果您过去使用过分析型系统,可能会认为 DuckDB 无法处理事务型工作负载。但 DuckDB 自诞生之日起就是作为支持完整 MVCC 和事务隔离的事务型、多连接数据库构建的。大多数用户只是在单用户场景中从未需要此功能。事实证明,DuckDB 能很好地处理事务:在相当多的工作负载中,它的速度足以与 PostgreSQL 等通用数据库竞争,而客户端/服务器模式终于让这套机制在多租户、长期运行的部署中大放异彩。
长期运行 DuckDB 也带来了新挑战,这就是为什么 v2.0 致力于改进指标、日志和可观测性(例如,参见 #22799(https://github.com/duckdb/duckdb/pull/22799)中的指标层重构),让您能够查看 DuckDB 实例的实际运行情况。甚至在预览版发布几周内,就有人为 Quack 协议构建了独立客户端。我们以为是在扩展 DuckDB 以与其他 DuckDB 通信;但世界却说"不,不,不",然后构建了自己的客户端。谁能想到呢。
## 2. `VARIANT` 类型成为一等公民(https://duckdb.org/2026/08/17/duckdb-20-highlights#2-variant-becomes-a-first-class-citizen)
`VARIANT` 类型在 DuckDB v1.5(https://duckdb.org/2026/03/09/announcing-duckdb-150.html)中首次引入,可以将其理解为增强版 JSON。想象一下,如果 JSON 能够变得很快会怎样。与 JSON 类似,`VARIANT` 列可以在每一行中存储不同结构的数据。但与 JSON 不同,它不是文本格式:DuckDB 会自动检测半结构化数据中隐藏的公共结构并进行"切片",使其在存储中压缩良好,在查询中执行快速,而您无需声明任何模式。
这使得 `VARIANT` 非常适合实时日志摄取,其中类似 JSON 的记录流共享结构但随时间演变。在 v2.0 中,此管道端到端打通:从存储层直接执行切片操作(#20912(https://github.com/duckdb/duckdb/pull/20912))、提取下推至扫描层(#22478(https://github.com/duckdb/duckdb/pull/22478))、支持 Parquet 格式的切片 `VARIANT` 读写,以及一系列 `variant_*` 函数:
```sql
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);
```
展望未来(可能在 v2.0 发布后不久,但请不要过度期待),我们计划用 `VARIANT` 作为常规 `JSON` 类型的后端,这样现有的 JSON 工作负载无需修改任何查询即可获得所有这些好处。
## 3. 触发器(https://duckdb.org/2026/08/17/duckdb-20-highlights#3-triggers)
触发器一直是用户强烈期待的功能,DuckDB v2.0 完整地提供了它们:包括 `BEFORE` 和 `AFTER` 触发器、`FOR EACH ROW` 和 `FOR EACH STATEMENT`、通过 `REFERENCING OLD/NEW TABLE` 实现的过渡表、每个事件支持多个触发器、对触发表使用 `RETURNING` 子句,以及 `DROP TRIGGER`。
经典用例是审计表:系统中发生某事,触发器记录变化内容。例如:
```sql
CREATE TABLE target (id INTEGER, val INTEGER);
CREATE TABLE audit (id INTEGER, old_val INTEGER, new_val INTEGER);
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;
INSERT INTO target VALUES (1, 10), (2, 20);
UPDATE target SET val = val * 10 WHERE id <= 2;
SELECT * FROM audit;
```
id|old_val|new_val
---|---|---
1|10|100
2|20|200
触发器与长期运行的 DuckDB 服务自然契合,我们也计划在内部使用它们来构建即将推出的一些功能。它们在 SQL 层完全暴露,因此您可以利用它们构建自己的酷炫功能。
## 4. SQL 方言增强(https://duckdb.org/2026/08/17/duckdb-20-highlights#4-sql-dialect-additions)
一如既往,DuckDB 的 SQL 方言持续发展。以下是本发布周期中的一些亮点:
**`NEAREST` 连接**(#24137(https://github.com/duckdb/duckdb/pull/24137))让 Top-K 相似性搜索成为一个连接子句,适用于向量和嵌入工作负载:
```sql
SELECT q.user_id, t.product_id
FROM users q
INNER JOIN products t
APPROX NEAREST 2 BY SIMILARITY array_cosine_similarity(q.embedding, t.embedding);
```
**CTE 内的 DML 操作**(#21634(https://github.com/duckdb/duckdb/pull/21634)、#21997(https://github.com/duckdb/duckdb/pull/21997)、#24217(https://github.com/duckdb/duckdb/pull/24217))允许您将 `INSERT`、`UPDATE`、`DELETE` 和 `COPY` 作为管道步骤使用:
```sql
WITH moved AS MATERIALIZED (
DELETE FROM staging RETURNING *
)
INSERT INTO archive SELECT * FROM moved;
```
**嵌套模式**(#23492(https://github.com/duckdb/duckdb/pull/23492)、#24222(https://github.com/duckdb/duckdb/pull/24222))允许模式中包含子模式:
```sql
CREATE SCHEMA finance;
CREATE SCHEMA finance.reports;
CREATE TABLE finance.reports.q3 (revenue DECIMAL);
```
新的**变量语法**(#21194(https://github.com/duckdb/duckdb/pull/21194))允许您在任何允许表达式的地方使用 `$x`,不再需要繁琐的 `getvariable(...)`(https://duckdb.org/docs/current/sql/functions/utility.html#getvariable-variable_name):
```sql
SET VARIABLE threshold = 100;
SELECT * FROM orders WHERE amount > $threshold;
```
**JSON 变更函数** `json_set`、`json_insert`、`json_replace` 和 `json_remove`(#23786(https://github.com/duckdb/duckdb/pull/23786))终于允许您原地修改 JSON 文档:
```sql
SELECT json_set('{"a":1}', '$.b', '2');
```
json_set('{"a":1}', '$.b', '2')
{"a":1,"b":2}
**带有 `USING KEY`(https://duckdb.org/2025/05/23/using-key.html)聚合的递归 CTE**(#19481(https://github.com/duckdb/duckdb/pull/19481))使得纯 SQL 中实现迭代算法成为可能,其背后是下文所述重写的递归 CTE 引擎:
```sql
WITH RECURSIVE tbl(a, b) USING KEY (a, avg(b)) AS (
SELECT 1, 5
UNION
SELECT a, b - 1 FROM tbl WHERE b > 0
)
TABLE tbl;
```
a|b
---|---
1|2.5
此外还有更多:SQL 标准的 `FETCH FIRST 2 ROWS ONLY`(#23533(https://github.com/duckdb/duckdb/pull/23533))、`OVERLAY()`(#22456(https://github.com/duckdb/duckdb/pull/22456))、`GROUP BY` 中的 `UNNEST`(#23644(https://github.com/duckdb/duckdb/pull/23644)),以及明确定义的 `MERGE`/`UPDATE ... FROM` 语义(用于多匹配行,#24058(https://github.com/duckdb/duckdb/pull/24058))。
## 5. 异步 I/O(https://duckdb.org/2026/08/17/duckdb-20-highlights#5-asynchronous-io)
与 S3 等对象存储的交互是 DuckDB 体验的核心:您的数据必须来自某处,而它通常存储在对象存储中。DuckDB 长期以来能够并行从对象存储读取数据,但同步访问限制了其速度。DuckDB v2.0 在整个引擎中引入了异步 I/O。我们在一篇专门的博客文章中详细描述了设计(https://duckdb.org/2026/07/31/asynchronous-io.html)。
得益于异步访问,I/O 层现在可以独立于查询处理层进行扩展,这意味着远程读取的并行度更高,网络存储上的查询速度显著提升。Parquet 支持率先推出(#23662(https://github.com/duckdb/duckdb/pull/23662)),随后是 CSV(#23961(https://github.com/duckdb/duckdb/pull/23961))和 DuckDB 自身的文件格式(#24654(https://github.com/duckdb/duckdb/pull/24654)),以及异步 Parquet 写入(#23283(https://github.com/duckdb/duckdb/pull/23283))和新的 `MMAP` 及 `DIRECT_IO` 模式(#22988(https://github.com/duckdb/duckdb/pull/22988))。本地存储也有少许受益,但网络存储才是您将看到巨大提升的地方。
## 6. 全面查询加速(https://duckdb.org/2026/08/17/duckdb-20-highlights#6-faster-queries-across-the-board)
与每个版本一样,我们投入了大量工作使您现有的查询无需任何修改就能运行得更快。一些亮点:部分聚合现在被下推到连接之下(#22572(https://github.com/duckdb/duckdb/pull/22572)),冗余聚合被复用(#24543(https://github.com/duckdb/duckdb/pull/24543));递归 CTE 引擎被重写(#22211(https://github.com/duckdb/duckdb/pull/22211));聚合在超出内存时现在会溢出到磁盘(#24499(https://github.com/duckdb/duckdb/pull/24499));Windows CLI 的多线程结果物化速度提升约 2.2 倍(#24036(https://github.com/duckdb/duckdb/pull/24036))。
速度能提升多少?以下是一个可以在笔记本电脑上运行的微基准测试:在包含一百万条边的图上进行单源可达性查询,写为普通递归 CTE(https://duckdb.org/docs/current/sql/query_syntax/with.html)。
```sql
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(预览版)|0.12 s
如您所见,对于相同的递归查询,DuckDB v2.0 速度提升了约 40 倍(!)。行组剪枝能力大幅增强:最小-最大索引(区域映射)(https://duckdb.org/docs/current/sql/indexes.html#min-max-index-zonemap%20%})和 Parquet 布隆过滤器(https://duckdb.org/2025/03/07/parquet-bloom-filters-in-duckdb.html)现在可以跳过结构体、列表、十进制数、UUID、`IN` 过滤器甚至函数谓词的数据:
```sql
-- 这些现在会剪枝行组而非扫描它们:
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);
```
查询规划也变得**分区感知**(#22336(https://github.com/duckdb/duckdb/pull/22336))。湖仓格式(https://duckdb.org/docs/current/lakehouse_formats.html)(DuckLake、Iceberg 以及 S3 上普通的 Hive 分区 Parquet)都是分区的,利用这种分区优势通常是扫描整个数据集与跳过大部分数据之间的区别。在 v2.0 中,规划器和优化器充分利用了现有分区,分区写入也进行了重构(#22225(https://github.com/duckdb/duckdb/pull/22225)、#22620(https://github.com/duckdb/duckdb/pull/22620))。
## 7. 存储格式 v2.0(https://duckdb.org/2026/08/17/duckdb-20-highlights#7-storage-format-v20)
DuckDB v2.0 将默认存储格式版本(https://duckdb.org/docs/current/internals/storage.html)提升至 v2.0.0(#22875(https://github.com/duckdb/duckdb/pull/22875))。主要变化是缓冲区管理的 ART 索引(#21458(https://github.com/duckdb/duckdb/pull/21458)、#23605(https://github.com/duckdb/duckdb/pull/23605)):索引不再固定在内存中,这意味着拥有大型索引的表可以瞬间打开,且其索引会按需分页加载。列元数据现在是懒加载的(#22333(https://github.com/duckdb/duckdb/pull/22333)),因此宽表的打开速度也更快。`DICT_FSST` 字符串压缩方法默认启用(#23733(https://github.com/duckdb/duckdb/pull/23733)),删除操作被紧凑存储(#24336(https://github.com/duckdb/duckdb/pull/24336)),并且存储层在读取时执行更强的损坏验证。简而言之:拥有大型索引和宽表的数据库打开更快,内存占用也大幅减少。
## 8. 全新的 SQL 解析器(https://duckdb.org/2026/08/17/duckdb-20-highlights#8-a-brand-new-sql-parser)
DuckDB 一直以使用源自 PostgreSQL 的解析器而闻名。我们决定是时候改变了:v2.0 搭载了我们自己的现代、可扩展的 PEG 解析器(#22194(https://github.com/duckdb/duckdb/pull/22194)),这是我们首次在 2024 年关于运行时可扩展解析器(https://duckdb.org/2024/11/22/runtime-extensible-parsers.html)的文章中探索的理念。此变更与扩展生态系统紧密相连:扩展现在可以钩入语法本身,因此请期待暴露全新 SQL 语法的扩展。它还带来了更清晰的错误消息和精确的源码位置,以及第一个方言兼容性模式:
```sql
SET dialect_compatibility_mode = 'spark';
```
由于我们设计它与旧解析器兼容,您应该不会注意到解析器更换带来的任何变化。如果确实注意到了,请提交问题报告。
## 9. 无需 ICU 的时区、日历和排序规则(https://duckdb.org/2026/08/17/duckdb-20-highlights#9-timezones-calendars-and-collations-without-icu)
DuckDB 中支持时区的时间戳、日历和排序规则一直
相似文章
DuckDB v2.0 预览
DuckDB v2.0,代号 Cyanoptera,预览了新功能,包括服务器模式、触发器、VARIANT 类型、异步 I/O 和新的 SQL 解析器,将于今年秋季发布。
DuckDB V2 基于PEG的SQL解析器
DuckDB v2.0 将其源自PostgreSQL的SQL解析器替换为基于PEG的解析器,后者更易于演进,并且能够在运行时扩展。
DuckDB 1.5.2 – 可在笔记本、服务器、浏览器中运行的 SQL 数据库
DuckDB 1.5.2 带来生产就绪的 DuckLake v1.0 湖仓格式、Iceberg 扩展改进、Jepsen 测试,以及支持文件存储的全新浏览器 Shell。
DuckDB 2.0 为何更快
MotherDuck 的技术博客详细解析 DuckDB 2.0 alpha 版本为何更快,重点介绍了通过独立下载线程池实现的异步 I/O,使 S3 上的 Parquet 查询性能显著提升,并分享了实际基准测试数据。
DuckDB: it's not quack science
DuckDB是一个开源嵌入式分析型数据库,支持直接查询文件、嵌入应用,并提供友好的SQL扩展,在数据分析场景下比传统Unix管道更高效。