宣布推出 DuckDB 1.5.0

DuckDB团队
2026-03-09 · 16 分钟阅读

简而言之:我们正式发布了 DuckDB 1.5.0 版本,代号为“Variegata”。此版本带来了更友好的 CLI(一个全新、更符合人体工程学的命令行客户端)、对 VARIANT 类型的支持、内置的 GEOMETRY 类型,以及许多其他功能和优化。v1.4.0 LTS 版本(“Andium”)将继续接收更新,直到 2026 年 9 月结束支持。

我们很自豪地发布了 DuckDB v1.5.0,代号为“Variegata”,该名称源自新西兰特有的天堂麻鸭(Tadorna variegata)。

在这篇博文中,我们将介绍此版本在支持、功能和扩展方面最重要的更新。一如既往,还有更多精彩内容:有关完整的发行说明,请参阅 GitHub 上的发布页面

要安装新版本,请访问安装页面。请注意,由于需要额外的更改和审查周期,某些扩展(例如 UI)和客户端库(例如 Go、R、Java)的发布可能需要几天时间。

随着本次发布,我们将提供两个 DuckDB 版本:v1.4 (LTS) 和 v1.5 (当前版本)。计划于 9 月发布的下一个版本将是一个大版本:DuckDB 2.0。

新功能

命令行客户端

对于使用终端操作 DuckDB 的用户,新版本的一大亮点是重构了 CLI 客户端,采用了新的配色方案、动态提示符、分页器以及许多其他便捷功能。

配色方案

我们发布了新的配色方案并将其与文档保持统一。该配色方案同时支持深色模式和浅色模式。两者都使用了两种灰色色调,并为关键字、字符串、错误、函数和数字分配了五种特定颜色。您可以在设计手册中找到此配色方案。

您可以使用 .highlight_colors 点命令自定义配色方案

.highlight_colors column_name darkgreen bold_underline
.highlight_colors numeric_value red bold
.highlight_colors string_value purple2
FROM ducks;

DuckDB CLI light mode DuckDB CLI dark mode

CLI 中的动态提示符

DuckDB v1.5.0 在 CLI 中引入了动态提示符(PR #19579)。默认情况下,这些提示符会显示您当前连接的数据库和架构。

duckdb
memory D ATTACH 'my_database.duckdb';
memory D USE my_database;
my_database D CREATE SCHEMA my_schema;
my_database D USE my_schema;
my_database.my_schema D ...

这些提示符可以通过括号代码进行配置,以设置最大长度、运行自定义查询、使用不同颜色等(#19579)。

.tablesDESCRIBE

要显示单个表的列,请使用 DESCRIBE 语句

memory D ATTACH 'https://blobs.duckdb.org/data/animals.db' AS animals_db;
memory D USE animals_db;
animals_db D DESCRIBE ducks;
┌──────────────────────┐
│        ducks         │
│                      │
│ id           integer │
│ name         varchar │
│ extinct_year integer │
└──────────────────────┘

.tables 点命令会列出已挂载的目录、其中的架构和表,以及每个表中的列。

memory D ATTACH 'https://blobs.duckdb.org/data/animals.db' AS animals_db;
memory D ATTACH 'https://blobs.duckdb.org/data/numbers1.db';
memory D .tables
 ────────────── animals_db ───────────────
 ───────────────── main ──────────────────
┌─────────────────┐┌──────────────────────┐
│      swans      ││        ducks         │
│                 ││                      │
│ id      integer ││ id           integer │
│ name    varchar ││ name         varchar │
│ species varchar ││ extinct_year integer │
│ color   varchar ││                      │
│ habitat varchar ││        5 rows        │
│                 │└──────────────────────┘
│     3 rows      │
└─────────────────┘
  numbers1
 ── main ──
┌──────────┐
│   tbl    │
│          │
│ i bigint │
│          │
│  2 rows  │
└──────────┘

使用 _ 访问上一次的结果

您可以使用下划线字符 _ 直接内联访问上一次查询的结果。这不仅方便,而且避免了重新运行可能耗时较长的查询。

memory D ATTACH 'https://blobs.duckdb.org/data/animals.db' AS animals_db;
memory D USE animals_db;
animals_db D FROM ducks WHERE extinct_year IS NOT NULL;
┌───────┬──────────────────┬──────────────┐
  id          name        extinct_year 
 int32      varchar          int32     
├───────┼──────────────────┼──────────────┤
     1  Labrador Duck             1878 
     3  Crested Shelduck          1964 
     5  Pink-headed Duck          1949 
└───────┴──────────────────┴──────────────┘
animals_db D FROM _;
┌───────┬──────────────────┬──────────────┐
  id          name        extinct_year 
 int32      varchar          int32     
├───────┼──────────────────┼──────────────┤
     1  Labrador Duck             1878 
     3  Crested Shelduck          1964 
     5  Pink-headed Duck          1949 
└───────┴──────────────────┴──────────────┘

分页器

最后但同样重要的一点是,CLI 现在有了分页器!当结果超过 50 行时,它会自动触发。

memory D .maxrows 100
memory D FROM range(0, 100);

在 Linux 和 Windows 上,您可以使用 Page Up / Page Down 进行导航。在 macOS 上,请使用 Fn + Up / Down。要退出分页器,请按 Q

分页器的初始实现由 tobwen#19004 中提供。

PEG 解析器

DuckDB v1.5 发布了一个基于 PEG(解析表达式语法)的实验性解析器。新解析器能够提供更好的建议、改进的错误消息,并允许扩展程序扩展语法。PEG 解析器目前默认处于禁用状态,但您可以选择启用:

CALL enable_peg_parser();

PEG 解析器已被用于生成建议。您可以使用 TAB 键在选项之间循环切换。

animals_db D FROM ducks WHERE habitat IS 
IS           ISNULL       ILIKE        IN           INTERSECT    LIKE

我们计划在下一个 DuckDB 版本中切换到新解析器。

作为权衡,该解析器会有轻微的性能开销,但在毫秒级范围内,对于分析型查询来说可以忽略不计。关于使用 PEG 解析器的基本原理和基准测试结果,请参考 Hannes 和 Mark 在 CIDR 2026 发表的论文,或他们总结该论文的博文

VARIANT 类型

DuckDB 现在原生支持 VARIANT 类型,该类型灵感来源于 Snowflake 的半结构化 VARIANT 数据类型,并且自 2025 年起在 Parquet 中可用。与物理存储为文本的 JSON 类型不同,VARIANT 存储的是带类型的二进制数据。VARIANT 列中的每一行都包含其自身的类型信息。这带来了更好的压缩效果和查询性能。以下是使用 VARIANT 的几个示例。

在同一列中存储不同类型

CREATE TABLE events (id INTEGER, data VARIANT);
INSERT INTO events VALUES
    (1, 42::VARIANT),
    (2, 'hello world'::VARIANT),
    (3, [1, 2, 3]::VARIANT),
    (4, {'name': 'Alice', 'age': 30}::VARIANT);

SELECT * FROM events;
┌───────┬────────────────────────────┐
│  id   │            data            │
│ int32 │          variant           │
├───────┼────────────────────────────┤
│     1 │ 42                         │
│     2 │ hello world                │
│     3 │ [1, 2, 3]                  │
│     4 │ {'name': Alice, 'age': 30} │
└───────┴────────────────────────────┘

检查每一行的底层类型

SELECT id, data, variant_typeof(data) AS vtype
FROM events;
┌───────┬────────────────────────────┬───────────────────┐
│  id   │            data            │       vtype       │
│ int32 │          variant           │      varchar      │
├───────┼────────────────────────────┼───────────────────┤
│     1 │ 42                         │ INT32             │
│     2 │ hello world                │ VARCHAR           │
│     3 │ [1, 2, 3]                  │ ARRAY(3)          │
│     4 │ {'name': Alice, 'age': 30} │ OBJECT(name, age) │
└───────┴────────────────────────────┴───────────────────┘

您可以使用点表示法或 variant_extract 函数从嵌套的变体中提取字段

SELECT data.name FROM events WHERE id = 4;
-- or 
SELECT variant_extract(data, 'name') AS name FROM events WHERE id = 4;
┌─────────┐
│  name   │
│ variant │
├─────────┤
│ Alice   │
└─────────┘

DuckDB 还支持从 Parquet 文件中读取 VARIANT 类型,包括分片存储(将嵌套数据存储为扁平值)。

read_duckdb 函数

read_duckdb 表函数可以在不先挂载的情况下读取 DuckDB 数据库。这使得从 DuckDB 数据库读取数据更加方便——例如,您可以使用 glob 匹配。您可以按照以下方式读取示例 numbers 数据库

SELECT min(i), max(i)
FROM read_duckdb('numbers*.db');
┌────────┬────────┐
│ min(i) │ max(i) │
│ int64  │ int64  │
├────────┼────────┤
│      1 │      5 │
└────────┴────────┘

Azure 写入

您现在可以使用 COPY 语句写入 Azure Blob 或 ADLSv2 存储

-- Write query results to a Parquet file on Blob Storage
COPY (SELECT * FROM my_table)
TO 'az://my_container/path/output.parquet';

-- Write a table to a CSV file on ADLSv2 Storage
COPY my_table
TO 'abfss://my_container/path/output.csv';

ODBC 扫描器

我们现在发布了 ODBC 扫描器扩展。这允许您按如下方式查询远程端点

LOAD odbc_scanner;
SET VARIABLE conn = odbc_connect('Driver={Oracle Driver};DBQ=//127.0.0.1:1521/XE;UID=scott;PWD=tiger;');
SELECT * FROM odbc_query(getvariable('conn'), 'SELECT SYSTIMESTAMP FROM dual;');

在接下来的几周内,我们将发布文档页面并发布一篇关于 ODBC 扫描器的后续文章。在此期间,请参阅项目的 README

重大变更

湖仓一体 (Lakehouse) 更新

DuckDB 支持的所有湖仓一体格式在 v1.5 中都收到了一些更新。

DuckLake

DuckDB v1.5 中主要的 DuckLake 变更是将 DuckLake 规范更新至 v0.4。我们旨在使其与将于 4 月发布的 DuckLake 1.0 的规范保持一致。其主要亮点包括:

  • 宏支持。
  • 排序表。
  • 删除内联和添加部分删除文件。
  • DuckLake 选项的内部重构。

我们将在 DuckLake v1 的博文中宣布关于这些功能的更多细节。

Delta Lake

对于 Delta Lake 扩展,团队重点改进了对通过 Unity Catalog 进行写入的支持、Delta 幂等写入以及表 CHECKPOINT

Iceberg

对于 Iceberg 扩展,团队正在为 v1.5.1 做一个更大的发布。对于 v1.5.0,主要功能是在 CREATE TABLE 语句中增加了表属性。

CREATE TABLE test_create_table (a INTEGER)
WITH (
    'format-version' = '2', -- format version will be elevated to format-version when creating a table
    'location' = 's3://path/to/data', -- location will be elevated to location when creating a table
    'property1' = 'value1',
    'property2' = 'value2'
);

其他小的添加包括允许在挂载 Iceberg 目录时传递 EXTRA_HTTP_HEADERS,这已经解锁了 Google 的 BigLake

Delta 和 DuckLake 都已实现 VARIANT 类型。Iceberg 的 VARIANT 类型将在 v1.5.1 版本中发布,届时还会包含一些 Iceberg v3 规范特有的其他功能。

网络栈

httpfs 扩展的默认后端已从 httplib 更改为 curl。作为最受欢迎且经过良好测试的开源项目之一,我们预计 curl 将为 DuckDB 提供长期的稳定性和安全性。无论使用哪种 http 库,openssl 仍然是底层的 SSL 库,且 http_timeouthttp_retries 等选项保持不变。

我们的社区在过去几周一直在测试新的网络栈。如果遇到任何问题,请提交到 duckdb-httpfs 存储库

如果您有兴趣了解更多细节,请点击这里。

由于技术原因,httplib 仍然是我们用于下载 httpfs 扩展的库。当使用(现已默认的)curl 后端加载 httpfs 时,后续的扩展安装将通过 https:// 进行,核心扩展的默认端点指向 https://extensions.duckdb.org

所有核心和社区扩展均已进行加密签名,因此通过 http:// 安装不会造成安全风险。然而,一些用户报告了在有防火墙的环境中安装 http:// 扩展时遇到的问题。

Lambda 语法

直到 DuckDB v1.2,定义 lambda 表达式的语法一直使用箭头符号 x -> x + 1。虽然这种语法很美观,但由于运算符优先级问题,它与 JSON 提取运算符 (->) 产生了冲突,导致了一些用户难以排查的错误消息。为了解决这个问题,我们在 v1.3 中引入了 Python 风格的 lambda 语法lambda x: x + 1

虽然 DuckDB v1.5 支持两种编写 lambda 表达式的风格,但使用已弃用的箭头语法现在会抛出警告。

SELECT list_transform([1, 2, 3], x -> x + 1);
WARNING:
Deprecated lambda arrow (->) detected. Please transition to the new lambda syntax, i.e., lambda x, i: x + i, before DuckDB's next release.

您可以使用 lambda_syntax 配置选项来更改此行为,以抑制警告或使其表现得更严格。

-- Suppress the warning
SET lambda_syntax = 'ENABLE_SINGLE_ARROW';
-- Turn the deprecation warning into an error
SET lambda_syntax = 'DISABLE_SINGLE_ARROW';

DuckDB 2.0 将默认禁用单箭头语法,仅在显式启用后才可用。

空间扩展

空间扩展 (Spatial extension) 发布了几个重要的变更。

重大变更:轴顺序翻转

spatial 中的大多数函数在笛卡尔空间中运行,不受轴顺序的影响,例如 XY 轴是代表“经度”和“纬度”还是相反。但在某些函数中,这很重要,并且反直觉的假设是所有输入几何图形都使用 (x = 纬度, y = 经度)。这些函数包括:

  • ST_Distance_Spheroid
  • ST_Perimeter_Spheroid
  • ST_Area_Spheroid
  • ST_Distance_Sphere
  • ST_DWithin_Spheroid

此外,ST_Transform 也期望输入几何图形的轴顺序与源坐标参考系统定义的相同,例如在 EPSG:4326 的情况下,这也是 (x = 纬度, y = 经度)。

这是一个长期存在的困惑来源和大量问题的根源,因为其他数据库、格式和 GIS 系统往往倾向于始终将 X 视为“东距”、“左右”或“经度”,将 Y 视为“北距”、“上下”或“纬度”。

我们正在更改 DuckDB 中的工作方式,以使其与系统的其他部分保持一致,并希望在未来减少新用户的困惑。然而,为了避免静默破坏已适应这种特性的现有工作流程(例如通过使用 ST_FlipCoordinates),我们通过一个新的 geometry_always_xy 设置逐步推广此更改。

  • 在 DuckDB v1.5 中,设置 geometry_always_xy = true 将启用新行为(x = 经度, y = 纬度)。如果不设置,受影响的函数会发出警告。
  • 在 DuckDB v2.0 中,该警告将变为错误。请设置 geometry_always_xy = false 以保持旧行为。
  • 在 DuckDB v2.1 中,geometry_always_xy = true 将成为默认值。

总结一下:在此版本中,默认设置不会发生任何更改,但为了避免将来受到此更改的影响,请现在显式设置 geometry_always_xy。将其设置为 true 以选择新行为,或设置为 false 以保持现有行为。

几何图形重构

GEOMETRY 成为内置类型

GEOMETRY 类型已从 spatial 扩展中移入 DuckDB 核心!

地理空间数据不再是小众需求。Parquet 标准现在将 GEOMETRY 视为一等列类型,而像 Apache Iceberg 和 DuckLake 这样的开放表格式也正朝着同一方向发展。许多广泛使用的数据格式和系统也有地理空间对应项——GeoJSON、PostGIS、GeoPandas、GeoPackage/Spatialite 等。

DuckDB 已经提供了与其中许多格式和系统集成的扩展。但存在一个结构性问题:只要 GEOMETRY 位于 spatial 扩展中,其他想要读取或写入地理空间数据的扩展要么必须依赖 spatial,实现自己的不兼容几何表示,要么强迫用户自己处理转换。

通过将 GEOMETRY 移入 DuckDB 核心,扩展程序现在可以原生生成和消费几何值,而无需依赖 spatial。虽然 spatial 扩展仍然提供处理几何图形的大部分函数,但类型本身成为了整个生态系统可以构建的共同基础。我们已经为 Postgres 扫描器添加了 GEOMETRY 支持,并为 Arrow 导入和导出添加了 GeoArrow 转换。更多扩展中的几何支持即将推出。

此更改还实现了与 DuckDB 存储引擎和查询优化器的更深度集成,解锁了当 GEOMETRY 仅作为扩展类型存在时无法实现的压缩技术、查询优化和 CRS 感知能力。这一切都在文档中新的几何页面中进行了说明,但我们在下面重点介绍一些内容。

改进的存储:WKB 和分片存储

几何值现在使用行业标准的小端序 熟知二进制 (WKB) 编码存储,取代了 spatial 扩展使用的自定义格式。但是,我们仍在试验要在执行引擎中使用的内存中表示,因此在数据进出 DuckDB 时,仍应使用转换函数(例如 ST_AsWKTST_AsWKBST_GeomFromTextST_GeomFromWKB)。

我们还为 GEOMETRY 实现了专门的存储技术。当几何列包含所有类型和顶点维度相同的数值时,DuckDB 可以额外应用“分片存储 (shredding)”:列被分解为原始的 STRUCTLISTDOUBLE 段,而不是存储不透明的 blob,这压缩效率要高得多。对于点云等均匀几何列,这可将磁盘占用空间减少约 3 倍。分片存储会自动应用于特定大小的均匀行组,但可以通过 geometry_minimum_shredding_size 配置选项进行配置。

几何统计和查询优化

几何列现在跟踪每个行组的统计信息——包括边界框以及存在的几何类型集和顶点维度。查询优化器可以使用这些信息来跳过无法与查询的空间谓词匹配的行组,类似于数值列的最小/最大值修剪。&&(边界框交集)运算符是第一个受益者;更广泛的 spatial 函数支持正在进行中。

坐标参考系统 (CRS) 支持

GEOMETRY 类型现在接受可选的 CRS 参数(例如 GEOMETRY('OGC:CRS84')),使 CRS 成为类型系统的一部分,而不是隐含的元数据。空间函数会在输入之间强制执行 CRS 一致性,从而捕获在混合来自不同坐标系统的几何图形时出现的常见静默错误。默认情况下只内置了几个 CRS,但加载 spatial 扩展会从 EPSG 数据集中注册超过 7,000 个 CRS。虽然 CRS 支持仍处于实验阶段,但我们正计划进一步开发它以支持例如自定义 CRS 定义。

优化

非阻塞检查点 (Non-Blocking Checkpointing)

在检查点期间,现在可以运行并发读取(#19867)、写入(#20052)、带有索引的插入(#20160)和删除(#20286)。检查点的重构有利于并发读写工作负载,并将 TPC-H 在 SF100 上的吞吐量评分从 246,115.60 提高到了 287,122.97,提升了 17%

聚合

聚合函数收到了一些优化。例如,社区成员 xe-nvdklast 聚合函数进行了优化,使其从每个向量批次的末尾而不是开头进行迭代。在合成基准测试中,这带来了 40% 的速度提升

分发

Python Pip

您可以在任何支持 pip 的平台上安装 DuckDB CLI。

pip install duckdb-cli

然后您可以在虚拟环境中使用以下命令启动 DuckDB:

duckdb

DuckDB v1.4 和 v1.5 均受支持。我们正在致力于使用 duckdb[extension_name] 语法将扩展作为额外功能发布——敬请关注!

Windows 安装脚本 (Beta)

在 Windows 上,您现在可以使用安装脚本:

powershell -NoExit iex (iwr "https://install.duckdb.org/install.ps1").Content

请注意,这目前处于测试阶段。如果您有任何反馈,请告知我们

适用于 musl libc 的 Linux CLI

我们正在分发适用于 musl libc 的 CLI 客户端(例如用于 Docker 镜像中常用的 Alpine Linux)。这些压缩包可在 GitHub 上获得。

请注意,musl libc CLI 客户端需要 libstdc++。要安装此包,请运行:

apk add libstdc++

扩展大小

我们重构了构建系统以减小扩展二进制文件的大小!DuckLake 扩展的大小减少了约 30%,从 17 MB 降至 12 MB。对于 Excel 等较小的扩展,减小幅度超过 60%,从 9 MB 降至 3 MB。

总结

以上只是一些亮点,但此版本还有更多功能和改进。自 v1.4 以来,近 100 位贡献者提交了超过 6500 次代码提交。完整的发行说明可以在 GitHub 上找到。我们要感谢社区提供的详细问题报告和反馈。再次特别感谢外部贡献者!

附:如果您是通过直接链接访问这篇博文的——我们还推出了新的登录页面

附录:示例数据集

查看创建示例数据库的代码。
ATTACH 'numbers1.db';
ATTACH 'numbers2.db';
ATTACH 'animals.db';

CREATE TABLE numbers1.tbl AS FROM range(1, 3) t(i);

CREATE TABLE numbers2.tbl AS FROM range(2, 6) t(i);

CREATE TABLE animals.ducks AS
FROM (VALUES
    (1, 'Labrador Duck', 1878),
    (2, 'Mallard', NULL),
    (3, 'Crested Shelduck', 1964),
    (4, 'Wood Duck', NULL),
    (5, 'Pink-headed Duck', 1949)
) t(id, name, extinct_year);

CREATE TABLE animals.swans AS
FROM (VALUES
    (1, 'Aurora', 'Mute Swan', 'White', 'European lakes and rivers'),
    (2, 'Midnight', 'Black Swan', 'Black', 'Australian wetlands'),
    (3, 'Tundra', 'Tundra Swan', 'White', 'Arctic and subarctic regions')
) t(id, name, species, color, habitat);

DETACH numbers1;
DETACH numbers2;
DETACH animals;