DuckDB Engineering Blog

18 篇内容

技术文章DuckDB Engineering Blog

Ducks in a Column

文章以 DuckDB 的列式存储为线索,解释分析查询为何只需读取命中的列,并串联起文件原地查询、通配符与 Hive 分区、投影/分区裁剪、列级 SQL、聚合快捷语法、窗口函数与 QUALIFY、ASOF JOIN,以及写出高压缩 Parquet 的排序、分区、窄类型和 EXPLAIN ANALYZE 验证。核心结论是让查询只读取所需列和值,可同时减少 I/O、提升压缩率并利用 zonemap 跳过数据块。文中示例具体、可操作,适合作为 DuckDB/SQL 分析实践参考;但内容偏官方特性导览,主要覆盖 DuckDB 方言和 Parquet 场景,对底层内核实现与其他数据库的差异讨论有限。

推荐收录:文章把列式存储原理与 DuckDB 的原地查文件、列级 SQL、聚合/窗口/ASOF、Parquet 分区排序等具体用法对应起来,并用 EXPLAIN ANALYZE 展示投影裁剪和分区跳过,证据充分。适合做数据分析、ETL 或本地/湖上查询的工程师作为可迁移的 SQL 与文件组织参考;风险是 DuckDB 方言和产品特性较强,跨数据库迁移时需注意等价语法与底层差异。

技术文章DuckDB Engineering Blog

From JSON Strings to Typed Columns

文章面向以 VARCHAR 存储 JSON 的列,介绍如何在 DuckDB 中不落盘、不 COPY 到文件,直接推断结构并转换为类型化列。核心流程是用 json_group_structure 汇总 JSON 结构,再用 json_merge_patch 覆盖字段类型,随后用 json_transform 解析并通过 unnest 展开字段。文中还讨论了递归展开的列名冲突、对象数组展开、json_transform 与 strict 版本对转换失败的不同处理,以及 VARCHAR 与 JSON 类型在存储和校验上的差异。结论是一次装载时完成 JSON 解析,后续查询直接使用普通类型化列,可避免重复解析并提升可读性。适用边界是大表可采样推断但可能漏掉稀有键,宽松转换会静默产生 NULL,需确认数据异常是否可接受。

推荐收录:文章给出了从 JSON 文本列到类型化列的完整 SQL 流程,包含结构推断、类型覆盖、递归展开和错误处理等可直接复用的操作细节。适合使用 DuckDB 或做 JSON/半结构化数据清洗的工程师参考,其中“采样推断可能漏键、宽松转换会静默置 NULL”的边界说明也便于迁移时评估风险。

工程实践DuckDB Engineering Blog

Benchmarking DuckDB v2.0-dev on NVIDIA Vera

DuckDB 工程博客在 NVIDIA Vera CPU 上对 v2.0-dev 预览版进行 TPC-H SF1000 全量基准测试,并与 Intel Xeon 6 x86 基线对比。测试使用 duckdb-tpch 工具链、768GB 内存与 NVMe SSD,Vera 使用 88 核并限制在单 socket,x86 使用 96 线程,同时设置内存分配器参数。三轮取中位数后,Vera 的 QphH@Size 为 3,073,292.99,x86 为 2,109,782.19,Vera 领先约 46%。作者将优势归因于高内存带宽、低内存延迟和 Olympus 核心的大缓存,有利于扫描、聚合与连接中的哈希表访问。不足是仅用预览版、单一 TPC-H 规模、单 socket 与厂商合作环境,结论需谨慎外推。

推荐收录:文章给出了可复现的 TPC-H SF1000 基准脚本、硬件配置、线程与内存参数,以及三轮中位数结果和 46% 差距,对数据库引擎性能评估和 CPU 选型有直接参考价值。适合数据库内核、查询引擎性能与硬件评测读者;但需注意其与 NVIDIA 合作、仅单基准单 socket 且使用预览版,跨平台结论应结合更多工作负载验证。

技术文章DuckDB Engineering Blog

What Is Inside an Iceberg Table?

本文以 DuckDB 的 iceberg 扩展为例,拆解 Apache Iceberg 表的磁盘结构:顶层 metadata.json、每快照一个 Avro manifest list、若干 manifest,以及底层 Parquet 数据文件和删除文件。作者用本地 REST catalog 创建按日期分区的示例表,执行两次插入和一次删除,再用 SQL 逐层读取,展示 snapshot 演进、摘要计数、manifest 内容、列统计与分区统计。核心结论是 Iceberg 文件不可变、提交只移动 catalog 指针,删除采用 merge-on-read 的 position delete 文件,统计信息用于跳过文件和分区。文章也提醒小提交与删除文件过多会拖慢查询,并说明 summary 字段可选、format-version 3 的 Puffin 删除向量未展开。

推荐收录。文章给出了可复现的 SQL 步骤,从 catalog 指针一路查到 manifest、列/分区统计和 position delete 文件,直接证据充分,能帮助数据工程师在查询变慢、行数异常或跨引擎写表时定位 Iceberg 表内部原因。其文件树、快照提交与统计跳过机制可迁移到 Iceberg 表布局审查和性能诊断;局限是示例较小且依赖本地 fixture,未覆盖所有引擎差异。

工程实践DuckDB Engineering Blog

Agent Mode in the DuckDB CLI

文章介绍 DuckDB v2.0 CLI 的 agent mode:当检测到 AI 编码代理(通过 AI_AGENT、CLAUDECODE、CODEX_CI 等环境变量)且 stdout 非终端、未指定输出格式时,自动切换到面向模型的输出。它把结果渲染为无对齐空白的 Markdown 表格,列类型放入表头;对大结果明确标注采样与省略行数,并给出结果哈希;达到上限后停止扫描、只报下界计数;错误以 JSON 输出,EXPLAIN 默认 compact 格式,长查询在执行前输出预估行数并定期报告进度。实验用 Claude Code 回答 TPC-H 100 的 22 道题,模型读取 token 从 123.6k 降至 50.8k,全部答案正确。但节省的 token 仅占每轮总输入约 0.5%,运行时间和总成本未降低,且 agent mode 轮次略多(237 对 224)。该模式可被 -agent、-no-agent、格式标志或 .duckdbrc 覆盖,检测约定也仍在演进。

推荐收录:文章不仅说明了 DuckDB CLI 如何通过环境变量检测 AI 代理,还给出了紧凑 Markdown 表格、截断标记、结果哈希、JSON 错误、提前终止和成本预估等具体设计取舍,并用 Claude Code 在 22 道 TPC-H 查询上将模型读取 token 从 123.6k 降到 50.8k 的实验验证其效果。对构建面向 agent 的 CLI、设计 LLM 可消费输出格式或优化工具链 token 成本的工程师有直接迁移价值;但作者也指出节省 token 占总输入比例很小,未降低总成本与运行时间,且检测约定尚未统一。

技术文章DuckDB Engineering Blog

A DuckDB Database with No Data in It

文章介绍如何创建一个不存储任何数据的 DuckDB 数据库文件,只用视图定义指向对象存储上的 Parquet 文件,从而把几百 KB 的文件当作整个数据湖的共享目录。作者演示安装 httpfs、创建持久化数据库、定义远程视图、上传目录文件以及只读 attach 的完整流程,并说明查询会按需读取远端列与行组。文章还展示当文件从单文件改为按年分区或列名变化时,只需替换视图即可保持消费者查询稳定。最后给出适用边界:消费者需能访问目录和所有底层数据、HTTPS/S3 连接只读、性能受网络和远端文件布局影响。

推荐收录。文章以可执行 SQL 和工作流说明 DuckDB 仅存视图的目录模式,涵盖创建、托管、只读挂载、schema 演化和限制,属于可迁移的数据湖共享目录设计。适合数据平台、DuckDB 用户和希望减少数据复制、向消费者暴露稳定关系集的工程师;但需注意网络凭证、只读限制与远端查询性能风险。

工程实践DuckDB Engineering Blog

Importing Data using Java Table Functions

文章源自 DuckDB 用户实战,为把 MongoDB 中一年的漏洞数据导入同服务器的 DuckDB,以支撑亚秒级分析查询和快速 Excel 导出,作者系统对比了四种 Java 侧导入方案。基准是 mongo 社区扩展,55 秒完成且查询低于 100ms,但因社区扩展缺乏未来兼容保证、团队又偏好用 Java 维护管道而被放弃。随后测试标准 JDBC 批量插入(3 分 37 秒,因 DuckDB 无原生批量插入、逐行开销大)和 Java Appender(2 分 2 秒,基于 2048 行 Data Chunk 真正批量刷新)。最终发现 mongo 扩展内部使用用户自定义表函数,改用 COPY over Java Table Function,配合 setMaxThreads(8) 与 preserve_insertion_order=FALSE 实现并行,达到 1 分 27 秒的最优 Java 方案。文章还讨论按天分批、导入后排序减小文件体积、磁盘空间约束等边界与取舍,并附可复用的开源代码。

推荐收录:文章给出四种导入方案在同一数据集上的实测耗时(55 秒到 3 分 37 秒)和完整实现代码,并解释性能差异根因,证据具体、可复现。对需要在 Java 中构建 DuckDB 或其他数据库摄取管道的数据工程师很有参考价值,其中表函数并行化、社区扩展长期维护风险和导入后排序权衡等经验可迁移到其他数据源与查询引擎。

技术文章DuckDB Engineering Blog

Faster String Aggregations with Dimension Tables

文章以 DuckDB 铁路站点数据为例,解释对重复长字符串做 GROUP BY 为何昂贵:哈希聚合需逐行哈希、比较并复制完整字符串,使哈希表变宽、缓存命中变差并可能提前落盘。作者提出维度表模式:先统计字符串基数,按字符串排序生成最窄无符号整数键,重写事实表为整数键,聚合后再回连维度表取字符串。聚合因此只处理定宽整数,小稠密键域可触发 perfect hash aggregate,排序键也保持字母序与确定性。文中还比较 ENUM、多字符串列与增量更新,并指出窄键无法减少高基数并发聚合的分组数,短字符串、近唯一列、一次性查询等场景不适用。适合数据库与数据分析从业者参考。

推荐收录。文章来自 DuckDB 工程博客,以真实查询模式给出可复现的维度表编码步骤、性能机制解释和适用边界,并包含 ENUM 对比与高基数并发聚合的反例。对数据库内核、查询优化和数据分析工程师而言,其中“窄整数键聚合、结果集回连维度表”的方法可直接迁移到重复长字符串的 GROUP BY 优化,同时文末的不适用清单能避免盲目套用。

技术文章DuckDB Engineering Blog

Jev and DuckDB: Plain-English Conditions in SQL

文章介绍 TypeSafe AI 发布的 Jev 模型与 DuckDB 的集成方式。Jev 不生成自然语言,而返回带概率的类型化结果:Noul 对应布尔谓词,Choice 对应枚举标签,Score 对应有序评分,因此可通过 jev()、jev_prob、jev_choice、jev_score 在 SQL 中实现自然语言过滤、分组和排序。文章梳理多个社区扩展在批量调用、缓存、并发、重试和输出类型上的设计差异,并给出批量处理 100 行约 0.211 秒等性能对比。作者也指出,扩展会把行内容发送给第三方 API,多数性能数据来自扩展作者自测,批次过大可能降低准确率,固定高吞吐任务用微调小模型或嵌入检索可能更便宜。适合关注 AI 与数据库查询引擎结合的读者,生产采用前需小样本验证并做基线对比。

推荐收录。文章不仅解释 Jev 的三种类型化输出,还具体展示 DuckDB 扩展如何把自然语言条件映射到 WHERE、GROUP BY 和 ORDER BY,并讨论批量、缓存、并发、重试与成本控制等工程细节。对数据库工程师和 AI 应用开发者有可迁移价值;但该生态尚早期,部分性能和准确率数字来自作者自测,生产采用前需做基线对比和敏感数据审查。

技术文章DuckDB Engineering Blog

DuckDB and Hugging Face: Querying Datasets Directly

文章介绍 DuckDB 通过 hf:// 协议直接查询 Hugging Face Hub 数据集的集成方案。自 v0.10.3 起,DuckDB 在 httpfs 扩展上支持 hf:// 路径,可把数据集仓库解析为 CSV、JSONL 或 Parquet 文件,无需先下载即可用 SQL 读取,并支持通配符扫描多文件、列裁剪、@ 版本固定和 ~parquet 分支。文章给出探索数据集、过滤采样、基准评测、与自有表连接和可复现分析等典型用例,还说明私有/门控数据集可通过 Secrets Manager 配置 token。边界在于公共数据集开箱即用,重复查询建议物化为本地表,整体更偏重官方用法与操作指南,未深入讨论远程读的性能模型和异常处理。

推荐收录:来源为 DuckDB 官方工程博客,提供了可直接运行的 SQL 代码、版本固定与私有数据集配置等具体证据,展示如何把 Hugging Face 数据集纳入本地 SQL 分析工作流。适合数据工程、ML 工程和需要快速探查/采样训练数据的读者,方法可迁移到其他远程 Parquet 数据集场景;主要不足是内容偏用法指南,缺少性能边界与失败模式的深入分析。

工具笔记DuckDB Engineering Blog

DuckDB Now Ships inside dbt v2

文章介绍 dbt v2(基于 Rust 的 Fusion 引擎)首次内置 DuckDB 适配器。作者回顾 v1 需单独安装 Python 包 dbt-duckdb,而 v2 改为 Rust 单仓 + ADBC 驱动,并自动下载缓存 DuckDB 驱动,配置一个 profile 即可运行。v2 新增 DuckLake 与 Iceberg REST 目录支持(需 use_catalogs_v2 标志)、将 dbt 元数据写成可查询 Parquet、提供原生 SQL 语义理解与列级血缘,并固定 DuckDB 版本以推下更多原生函数。迁移可先在 v1.12 用 opt-in v2 parser 验证,再用 dbt-autofix 和升级指南切换。文章偏功能与用法说明,缺少性能基准和取舍分析,适合使用 dbt/DuckDB 的数据工程读者。

推荐收录:文章给出了 dbt v2 内置 DuckDB 的配置方式、DuckLake/Iceberg catalog、Parquet 元数据查询和迁移路径,属于可操作的工具集成参考。适合数据工程师和分析工程师了解本地 dbt 工作流及 v2 迁移。需注意它偏功能公告,缺少性能与取舍验证,版本锁定可能带来后续适配成本。

技术文章DuckDB Engineering Blog

Persistent Databases in the Browser with DuckDB-Wasm and OPFS

文章介绍 DuckDB-Wasm 如何借助浏览器 Origin Private File System(OPFS)实现持久化数据库:通过 open({path: 'opfs://analytics.duckdb'}) 打开数据库文件,数据以标准 .duckdb 文件加 WAL 的形式落盘,可跨页面刷新和浏览器重启存活,无需 IndexedDB 封装或应用层序列化。文中给出完整代码示例,说明远程 Parquet 数据只在首次加载时通过 HTTP range 请求获取,之后由 OPFS 提供;并对比了 auto 与手动 registerOPFSFileName 两种文件处理模式在便利性和句柄开销上的取舍。持久性部分指出浏览器标签页很少被干净关闭,因此应在每批写入后显式执行 CHECKPOINT,或将 checkpoint_threshold 设为 0,否则 WAL 重放会拖慢下次打开。文章还提醒 OPFS 属于可能被浏览器回收的存储,应定位为本地缓存而非唯一数据副本,并演示了通过 OPFS API 或 COPY 到 Parquet 导出数据;同时给出仅支持单句柄、SQL 重命名受限、npm latest 版本存在路径规范化 bug 等边界。

推荐收录:这是 DuckDB 官方对浏览器内持久化数据库的机制级说明,包含可运行代码、WAL 与 checkpoint 的持久性权衡、文件句柄与版本兼容等真实约束,证据具体而非概念宣传。适合做 local-first Web 应用、浏览器端分析或 Wasm 存储选型的开发者,其中的检查点策略、缓存与真实数据源分层、导出路径等判断可直接迁移到类似离线优先系统。主要风险是 API 与版本行为仍在演进,读者需核对所固定版本与官方限制说明。

工程实践DuckDB Engineering Blog

How DuckDB Runs Recursive CTEs Faster

本文来自 DuckDB 工程博客,介绍了 v2.0 对递归 CTE 执行引擎的重构,目标是消除迭代间重复调度与重建状态的开销。核心方法是将物理算子树、预计算调度投影和可复用执行器池归查询计划所有,递归调用持有跨 epoch 的不变状态(如基于静态表构建的哈希表),每个 epoch 仅重置依赖前沿的状态,并通过精确的边界基数选择内联或并行调度。针对 USING KEY 递归,冻结键控状态以支持直接探测,内连接可用 RECURSIVE_KEY_JOIN 或部分键索引,并引入语义变化:UNION 仅转发最终发生变化的键,UNION ALL 仍转发全部候选。实验显示,在 100 万边可达性查询中延迟从 4.051 秒降至 0.095 秒,LDBC SF100 路径查询提速 6.55 倍且峰值内存下降,63 个递归基准几何均值改善 5.5%。适用边界包括:保留状态需可重复性证明,预聚合要求聚合状态可组合且无顺序依赖,宽唯一键更新场景有约 6% 的回归。

直接证据是作者为 DuckDB 核心开发者,提供了 PR 编号、EXPLAIN 分析与中位数基准对比,且讨论了语义变化与回归。适合数据库内核开发者、查询引擎研究者与对 SQL 递归性能优化感兴趣的读者。可迁移价值在于状态所有权划分、基于实测基数的自适应执行和变更键去重思想;风险是部分语义变更(UNION 改变行为)需使用者注意。

工程实践DuckDB Engineering Blog

DuckDB Table Functions in Java

文章介绍 DuckDB Java 客户端新增的纯 Java 表函数能力,允许开发者将任意 Java 可访问的数据源注册为 SQL 表,从而在单节点上完成跨远程系统与本地文件的异构查询,无需导出或中间表。作者以 MongoDB 为例,通过 DuckDBFunctions.tableFunction() 注册 mongo_query 函数,并详细说明 bind、init、apply 三个回调:bind 声明输出列,init 打开游标,apply 将数据按 2048 行向量块写入结果。文章强调该方式复用官方 Java 驱动、过滤条件下推到源端,且避免了原生扩展的构建与 JVM 崩溃风险。同时明确当前限制:表函数无法打包为 DuckDB 扩展,只能在 Java 客户端内使用;bind/init 对象生命周期需手动管理;STRUCT、LIST 等复合类型尚未支持。

文章来自 DuckDB 官方工程博客,提供了完整的表函数生命周期实现示例、与本地文件的交叉连接演示以及清晰的局限性说明,属于有深度且可直接迁移的工程实践。适合需要在 JVM 环境中将既有 Java SDK 或 JDBC 数据源接入 DuckDB 的工程师,可避开 C++ 扩展开发,降低维护风险。注意该 API 仍在演进,使用前应确认当前版本对生命周期管理和复合类型的支持。

工程实践DuckDB Engineering Blog

Chunked Query Results in the DuckDB Java Driver

文章介绍 DuckDB Java 驱动 1.5.3.0 新增的 chunked query results 功能,通过 DuckDBChunkedResult 让应用以惰性方式直接读取引擎生成的列式数据块,避免 JDBC ResultSet 逐行、逐值获取带来的开销。文章先解释了 DuckDB 的向量化执行与 JDBC 行式 API 的差异,指出传统驱动需要把 2048 行一列的数据块切片成行和单元格,导致不必要的转换成本。随后给出新 API 的使用示例,并总结了其特性:惰性拉取、列式访问、保留元数据、与 UDF 读取接口一致、使用零基索引。文章也明确列出了当前限制,包括仅支持基本类型、只适用于 prepared statement、reader 类型覆盖有限。结论强调 JDBC ResultSet 仍是大多数场景的合理默认,chunked API 面向返回大量数据且消费端也为列式的场景。

推荐收录,因为这是官方工程博客对新功能的设计与实现说明,清晰呈现了 JDBC 行式 API 与列式数据库引擎之间的适配问题,并给出了具体的新 API 用法、适用场景和当前局限。对需要在 Java 中高效消费 DuckDB 大结果集的开发者,以及关注数据库驱动和向量化执行接口设计的工程师,都有直接的参考价值。

工程实践DuckDB Engineering Blog

DuckDB v2.0: Your Database Deserves a Better Parser

本文是 DuckDB 工程团队关于 v2.0 用 PEG 解析器替换 PostgreSQL 派生解析器的深度技术说明。文章先阐明解析器在查询流水线中的角色,并区分了 DuckSQL 方言与解析器实现本身。接着指出旧的 YACC/Bison LALR(1) 解析器在扩展语法时容易引入 shift/reduce 冲突,而 PEG 通过有序选择避免了这类冲突。工程化过程中,作者重点解决了回溯导致的指数级重复工作,借助 packrat 记忆化使得恶意输入(如大量未闭合括号)的解析时间从指数级降为近乎常数,并给出实测数据。文章还演示了运行时扩展语法的方法:扩展可注册自定义规则并复用 DuckDB 既有语法与转换函数,以 Google pipe query syntax 为例展示了从语法到 AST 的完整过程。最后说明扩展 API 仍是预览,若发现现有查询行为不一致可提交 issue。该文对数据库解析器设计、语法扩展机制和解析性能优化具有长期参考价值。

本文基于真实工程改造,给出了从动机、原型到生产化的完整路径,包含 packrat 记忆化解决指数级回溯的性能对比数据,以及通过扩展点复用现有语法和转换函数的具体 API 示例。适合数据库内核、编译前端或开发者工具方向的工程师阅读。文中的运行时语法扩展思路与回溯性能治理方法可以迁移到其他解析器或语言实现;需注意扩展 API 仍为预览,兼容性验证细节未完全展开。

工程实践DuckDB Engineering Blog

Reconciling JSON in DuckDB, One Patch at a Time

本文是 DuckDB 工程博客的客座文章,介绍 DuckDB v2.0 JSON 扩展新增的四个标量函数:json_merge_patch_diff(计算 RFC 7396 merge patch 的逆)、json_deep_merge(null 表示跳过合并的递归合并)、json_normalize(递归排序键以生成规范形式)和 json_strip_nulls(递归删除 null 值键)。文章以 Atlan 的元数据同步场景为背景,展示这些函数如何组合成端到端的状态对账流程,用 SQL 单查询完成清洗事件、计算最小补丁、应用补丁和规范化哈希。作者在 50 万条合成 CDC 事件上对比了 Python 实现,DuckDB 获得 10 到 123 倍的加速,并说明性能来自 yyjson 原地操作和向量化执行。文章也明确了函数语义边界,如 SQL NULL 与 JSON null 的差异、数组元素顺序保留等。

推荐收录,因为这是一篇来自数据库核心团队的一手设计解读,包含函数语义、实现机制、组合用法和可复现基准,不是泛泛的功能介绍。对使用 DuckDB 做数据管道或 JSON 对账的工程师、数据库内核开发者都有直接借鉴价值,其 diff/merge/normalize/strip 的抽象也可迁移到其他数据处理系统。

技术文章DuckDB Engineering Blog

A Preview of DuckDB v2.0

DuckDB v2.0预览文章由核心开发者撰写,概述了即将发布的重大版本的主要特性。文章首先介绍了DuckDB作为服务器的新模式,通过Quack协议和CONNECT语句实现客户端/服务器架构,支持远程查询生产数据库。随后重点讲解了VARIANT类型的深化应用,使其能高效处理半结构化数据,并配合一系列variant_*函数。文章还介绍了触发器、丰富SQL方言(如NEAREST连接、CTE内DML、嵌套schema等)、全引擎异步I/O、大量查询性能优化(如重写递归CTE、聚合下推、分区感知规划)、新存储格式、全新PEG解析器,以及用自研实现替代ICU库带来的体积和性能优势。最后强调了稳定C API和自定义扩展仓库,使扩展编写和分发更加便捷。文章以预览形式呈现,强调细节可能在正式发布前调整,并提到部分破坏性变更。

本文是DuckDB官方工程博客的权威技术预览,内容详实,包含具体代码示例、性能基准和设计动机,展示了嵌入式数据库向客户端/服务器模式演进的关键架构决策。适合数据库内核工程师、数据分析平台开发者和对查询引擎优化感兴趣的读者。文中关于异步I/O、存储格式演进和扩展稳定ABI的设计思想具有可迁移性,但需注意各功能为预览状态,正式发布可能调整。