DuckDB、SQLite 与 WASM/OPFS

共 43 题
📑 题目列表 43 题
#
★★★

1. DuckDB 嵌入式 OLAP 引擎,支持列存与向量化执行

请说明 DuckDB 作为嵌入式 OLAP 引擎的核心架构,以及它如何通过列式存储与向量化执行实现高性能分析查询?

  • 嵌入式引擎与服务器式数据库的定位差异
  • 列存(Columnar Storage)与向量化执行引擎
  • 分析型(OLAP)工作负载的优化方向

DuckDB 是一个进程内(in-process)的嵌入式 OLAP 数据库,无需独立服务端进程,直接以库的形式嵌入应用进程,天然适合数据分析、ETL 与本地研发场景。其核心架构是列式存储与向量化执行引擎:数据按列存放,列内同类型数据便于压缩与 SIMD 批量处理;执行引擎以"一次处理一批(vector/batch)行"为单位,而非逐行迭代,从而显著减少解释开销与 CPU 指令数。DuckDB 还支持全局内存中的查询优化、多线程并行、列式压缩与统计信息裁剪,使单机在分析负载上能接近或超越许多传统数据库。

嵌入式 + 列存 + 向量化是关键组合。OLAP 查询通常扫描大量列的子集并做聚合,列存减少无关列 IO,向量化降低每行处理开销,多线程并行提升吞吐。DuckDB 没有传统服务器的网络/连接/并发负担,把这部分资源用于查询执行,因此在分析场景表现突出。

#
★★★

2. DuckDB 支持 window function、CTE、Pivot/Unpivot 等分析语法

说明 DuckDB 对现代分析 SQL 语法的支持,特别是窗口函数、CTE 与 Pivot/Unpivot 的组织方式?

  • 窗口函数(OVER、PARTITION BY、ORDER BY)
  • 公共表表达式(CTE)支持
  • Pivot/Unpivot 的语法与语义

DuckDB 完整支持 SQL:2016 标准中的分析语法。窗口函数通过 OVER 子句实现分区排序与聚合(如 ROW_NUMBER、RANK、LAG/LEAD、SUM OVER),并能与 ORDER BY 组合定义窗口框。CTE(WITH 子句)支持递归与嵌套,便于组织复杂分析逻辑。Pivot/Unpivot 是 DuckDB 的特色能力:PIVOT 将分类值旋转为列(宽表化),UNPIVOT 将多列还原为键值长表,二者在报表与数据透视场景中非常实用,且 DuckDB 的 PIVOT 还支持多列与聚合函数组合。

分析查询往往需要把行转列或列转行、做排名与移动计算,DuckDB 将这些高频能力内建为标准语法,避免在应用层用代码手工实现,既提升可读性也减少出错。

-- 窗口函数
SELECT dept, emp, salary,
       ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
FROM emp;
-- PIVOT:把类别行转为列
PIVOT sales ON quarter USING SUM(amount) GROUP BY product;
#
★★★

3. DuckDB 通过 ATTACH 接入 PostgreSQL/MySQL 数据库

说明 DuckDB 如何通过 ATTACH 语句连接并查询 PostgreSQL/MySQL 等外部数据库?

  • ATTACH 语法与外部数据库连接
  • 跨数据库查询(借助扩展)
  • 数据导入导出场景

DuckDB 通过 ATTACH 语句将一个外部数据库(如 PostgreSQL、MySQL、SQLite 等)作为"附加数据库"挂载到当前会话,之后即可用 schema.table 形式直接跨库查询。该功能依赖外部扩展(如 postgresmysql 扩展),连接时通过 DSN/连接串指定主机、端口、库名与凭据。ATTACH 后既可以在外部库上执行只读分析,也可以通过 COPY ... FROMCREATE TABLE ... AS SELECT 把外部数据拉入本地列存表做分析,是"数据湖/多库联合分析"的常用手段。

ATTACH 的价值在于把 DuckDB 作为统一分析入口,避免把数据全部复制一份。它复用了 DuckDB 的向量化执行来做下推与过滤,同时保留外部系统的数据主权。

ATTACH 'host=localhost port=5432 dbname=mydb' AS pg (TYPE postgres);
SELECT * FROM pg.public.orders WHERE amount > 100;
#
★★★

4. Turso 通过 Embedded Replicas 在客户端缓存数据

说明 Turso 如何通过 Embedded Replicas 在客户端本地缓存数据,以及这带来的读写模型与一致性特点?

  • libSQL/Turso 的分布式 SQLite 架构
  • Embedded Replicas(嵌入式副本)的本地缓存
  • 读写分离与最终一致性

Turso 是构建在 libSQL(SQLite 分支)之上的托管分布式 SQLite 服务,核心能力是"嵌入式副本"(Embedded Replicas)。它允许应用在本地嵌入一个 SQLite/libSQL 副本,把主库数据(通常是只读)同步到边缘或客户端本地,从而就近读取、降低延迟。本地副本通过复制机制持续获得主库更新;写入则一般转发到主库(或主可写副本)处理,再通过 WAL/复制回传本地。因此读取在本地的低延迟、写入在主库强一致,读的是近似实时(最终一致)的数据。

嵌入式副本把"数据库放在离用户最近的地方"作为核心,契合边缘计算与多地部署。其代价是读端可能看到旧数据(最终一致),需要业务在接受一致性与延迟之间权衡。

#
★★★

5. DuckDB 在 0.10+ 通过 SELECT * FROM 's3://...' 直接查询 Parquet

说明 DuckDB 0.10+ 如何通过直接读取 S3 上的 Parquet 文件进行查询,以及这一能力的产品意义?

  • 直接查询外部文件(S3/HTTP)
  • Parquet 列存与谓词下推
  • httpfs/s3 扩展

DuckDB 0.10 及以后版本通过 httpfs 扩展支持 SELECT * FROM 's3://bucket/path/*.parquet' 直接查询对象存储中的 Parquet 文件,无需先把数据导入本地。查询时 DuckDB 会读取 Parquet 的元数据(schema、行数、统计信息),进行谓词下推与列裁剪(只读取需要的列),并可并行读取多个文件与分片。这一能力让 DuckDB 能作为轻量级的"查询引擎"直接跑在数据湖/对象存储上,配合 glob 通配符可扫描分区。

直接读 S3 Parquet 意味着把"存储"与"计算"解耦,DuckDB 作为一次性分析引擎即查即用,无需建表、无需 ETL,接近 Serverless 分析体验,同时利用 Parquet 自带的统计信息裁剪减少 IO。

SELECT region, SUM(amount)
FROM read_parquet('s3://my-bucket/sales/*.parquet')
WHERE month = 202604
GROUP BY region;
#
★★★

6. SQLite 通过 WAL 模式支持多读单写并发

说明 SQLite 的 WAL(Write-Ahead Logging)模式如何实现多读单写并发,以及与传统 rollback journal 模式的差异?

  • WAL 日志机制
  • 读者与写者并发模型
  • 快照隔离与读一致性

在 WAL 模式下,SQLite 不直接修改数据库主文件,而是把更改先追加到独立的 WAL 文件中。读事务基于 WAL 中的内容构建一个一致性快照,多个读事务可以同时进行且互不阻塞;写事务则是串行的(同一时刻只有一个写者)。因此 WAL 实现了"多读单写"的并发模型:读者不会阻塞写者,写者也不会阻塞读者。相比传统的 rollback journal 模式(写时需要独占 DB 文件,读取被阻塞),WAL 显著提升了并发读场景的性能与响应性。

WAL 的代价是需要定期 checkpoint 把 WAL 内容合并回主库文件,且 WAL 文件会占用额外磁盘空间。在并发读多写少的嵌入式场景(如 Web、移动端)中,WAL 是首选模式。

#
★★

7. SQLite 通过 JSON1/JSONB 扩展支持 JSONB 函数

说明 SQLite 的 JSON1 扩展与 JSONB 支持,以及 JSON 函数在查询与存储中的应用?

  • JSON1 扩展的函数集
  • JSONB 二进制表示
  • 面向 JSON 的索引与查询

SQLite 自 3.38 起把 JSON1 扩展内置,提供 json_extractjson_objectjson_array->/->> 运算符等丰富 JSON 函数,可在 SQL 中解析、查询、构造与修改 JSON 数据。此外 SQLite 3.45+ 加入 JSONB 二进制内部表示(jsonb() 函数),比文本 JSON 更紧凑、查询更快。JSON 数据可通过表达式索引(对 json_extract 结果建索引)加速字段查询,使 SQLite 在一定规模内能承担"半结构化 + 文档"负载。

JSON 支持让 SQLite 在处理灵活、动态 schema 的数据时更友好,同时保持 SQL 查询能力。JSONB 牺牲了人类可读性但换来更小的存储与更快的解析,契合嵌入式场景。

SELECT json_extract(info, '$.name') AS name
FROM users
WHERE json_extract(info, '$.age') > 30;
#
★★

8. SQLite / WASM / OPFS 在 WASI Preview2、Component Model 上的沙箱与系统调用代理?

说明 SQLite 的 WASM 构建在 WASI Preview2 与 Component Model 下的沙箱机制与系统调用代理原理?

  • WASI 与 WASM 沙箱
  • Component Model 的接口抽象
  • 系统调用代理(WASI Preview2 的 I/O 接口)

SQLite 编译为 WASM 后运行在浏览器或 WASI 运行时中,受 WASM 沙箱约束:无法直接访问宿主文件系统、网络或进程,只能通过 WASI 提供的接口(Preview2 将文件、网络、时钟等抽象为基于 Capability 的接口)进行。WASI Preview2 采用 Component Model 的 WIT 接口定义,把"系统调用"封装为组件间接口调用,由嵌入方(浏览器/宿主)以"代理"方式实现,例如把文件操作映射到 OPFS 或 IndexedDB。这样可以做到最小权限、显式授权,提升安全性。

沙箱的本质是"能力安全"(capability-based security):应用只能使用宿主显式传入的接口,无法越权访问系统资源。WASI Preview2 + Component Model 使这种代理更规范、可组合,适合在浏览器与嵌入式环境中安全运行 SQLite。

#
★★

9. SQLite / WASM / OPFS 在 Cross-compilation(Zig、Clang)的 multi-arch 构建中的 toolchain 整合?

说明 SQLite 的 WASM/OPFS 版本在跨平台交叉编译(Zig、Clang)中对多架构 toolchain 的整合方式?

  • 交叉编译与 multi-arch
  • zig cc / clang 的 target 指定
  • WASM32 目标与 Emscripten

SQLite 的 WASM 版本通常用 Emscripten 或 wasm32-wasi 目标编译。在跨架构(multi-arch)构建中,Zig 的 zig cc 可作为通用交叉编译器,通过 -target 指定目标三元组(如 wasm32-wasi、wasm32-emscripten、x86_64-linux-gnu 等)一次编译多处;Clang 同样支持 --target 指定目标。toolchain 整合的关键在于把 C 源码、SQLite 的 amalgamation(单文件源)与目标平台的头文件/库正确绑定,并处理对齐、字节序、内存布局等平台差异,产出各平台均可加载的构建产物。

SQLite 以单一 C 源文件(amalgamation)分发,跨平台只需保证编译目标与内存模型正确,非常适合 Zig/Clang 的交叉编译流水线。CI 中可对多目标同时产出,确保一致的 API 行为。

#
★★

10. DuckDB 的扩展机制,INSTALL/LOAD 与 SQLite 的 load_extension 在安装、签名与版本管理上的差异?

对比 DuckDB 的 INSTALL/LOAD 扩展机制与 SQLite 的 load_extension 在安装、签名与版本管理上的差异?

  • DuckDB INSTALL/LOAD 扩展管理
  • SQLite load_extension 动态加载
  • 签名验证与版本管理

DuckDB 提供规范化的扩展管理:INSTALL 从官方扩展仓库下载扩展包,LOAD 加载已安装扩展,扩展带版本、签名与校验,与 DuckDB 版本绑定,安全性由官方签名保障。SQLite 的 load_extension 则是直接动态加载一个共享库(.so/.dll),需要用户显式启用(enable_load_extension),没有官方签名或统一版本管理,扩展的可靠性与安全性完全依赖来源。简言之,DuckDB 的扩展是"官方托管、签名、版本化"的,SQLite 的扩展是"自由动态库、无统一管理"。

差异源于产品定位:DuckDB 作为面向分析的产品希望扩展开箱即用且安全可控;SQLite 作为嵌入式库则保持极简,把加载能力交给宿主程序决定。这也解释了为什么下载第三方扩展时需关注可信度。

#
★★

11. SQLite 的 journal 模式(DELETE/TRUNCATE/PERSIST/WAL)在崩溃安全、并发与 IO 放大上的差异?

对比 SQLite 的几种 journal 模式(DELETE/TRUNCATE/PERSIST/WAL)在崩溃安全、并发与 IO 放大上的差异?

  • 各 journal 模式机制
  • 崩溃安全与原子性
  • 并发与 IO 放大

DELETE 模式(默认):回滚日志文件在事务提交后删除,每次删除/重建文件产生较多元数据 IO,且写库需独占(读被阻塞)。TRUNCATE:提交后把日志截断为零而非删除,减少文件系统操作开销,但同样需要独占写。PERSIST:提交后保留日志文件内容仅清零头,进一步减少元数据调整,兼顾崩溃安全与较低 IO。WAL:改动先写 WAL 文件,回滚日志语义被 WAL 取代,实现多读单写、写不阻塞读,崩溃恢复靠 WAL 重放,读写并发最好,但需要 checkpoint 与额外磁盘。整体上 DELETE/TRUNCATE/PERSIST 是"回滚日志"体系,WAL 是"预写日志"体系,后者的并发与 IO 特性更优。

崩溃安全上四者都保证事务原子性(崩溃后回滚或重放),差异在并发与 IO 放大。选择 TRUNCATE/PERSIST 是为减少 DELETE 的频繁文件创建开销,WAL 则面向并发读场景。

#
★★

12. DuckDB 读取 Parquet 时的元数据过滤(metadata filtering)与统计信息裁剪如何减少 IO?

说明 DuckDB 读取 Parquet 时如何利用元数据过滤与统计信息裁剪来减少 IO?

  • Parquet 行组统计信息
  • 谓词下推到文件/行组层面
  • 列裁剪

Parquet 文件在 footer 中保存每个 row group 的统计信息(min/max、null count)与 schema 元数据。DuckDB 读取时先解析 footer,利用元数据做两层裁剪:一是列裁剪,只读取查询涉及的列;二是行组裁剪,根据谓词(WHERE 条件)对比行组的 min/max 统计,跳过不满足条件的 row group,从而大幅减少实际读取的数据量。结合分区目录(按分区列出文件)与 glob 通配,还能跳过整个文件。这是"元数据过滤 + 统计信息裁剪"带来的 IO 收益。

Parquet 的统计信息使其具备"可裁剪性",DuckDB 把过滤条件下推到 row group 层面,实现"扫得少、读得快"。这对大文件、宽表离线分析尤其有效。

#
★★

13. DuckDB 与 PostgreSQL 的 SQL 方言差异(ILIKE、PIVOT、QUALIFY 等)在迁移分析 SQL 时的注意点?

说明 DuckDB 与 PostgreSQL 在 SQL 方言上的差异(如 ILIKE、PIVOT、QUALIFY)以及迁移分析 SQL 时的注意点?

  • 方言差异点(ILIKE、PIVOT、QUALIFY、类型函数)
  • 迁移改写策略
  • 兼容性测试

DuckDB 与 PostgreSQL 语法高度相似,但存在差异:PostgreSQL 用 ILIKE 做大小写不敏感匹配,DuckDB 同样支持 ILIKE;PIVOT/UNPIVOT 是 DuckDB 一等公民语法,PostgreSQL 需使用 crosstab 或 filter 聚合模拟;QUALIFY 用于过滤窗口函数结果,DuckDB 支持 QUALIFY,PostgreSQL 需要子查询包裹。函数与类型上也有差异(如 DuckDB 的 list_* 数组函数、struct 复合类型,PostgreSQL 用 array 与 jsonb)。迁移时需逐条核对语法、函数是否存在、类型映射(如 DuckDB 的 VARCHARTEXT 差异、整数除法语义),并做回归测试。

迁移分析 SQL 的核心是"语法等价"而非"字符等价"。PIVOT/QUALIFY 这类 DuckDB 特色语法在 PostgreSQL 中需改写为子查询或聚合,同时注意 NULL 语义、布尔比较、字符串拼接等细节差异。

#
★★

14. DuckDB 的 Arrow 集成,COPY ... TO/FROM FORMAT arrow 与内存中 Arrow 数据的零拷贝查询?

说明 DuckDB 与 Apache Arrow 的集成方式,包括 COPY 到 Arrow 格式与内存中 Arrow 数据的零拷贝查询?

  • Arrow 列存格式
  • COPY ... FORMAT arrow 导入导出
  • 零拷贝(Zero-copy)内存交换

DuckDB 与 Apache Arrow 深度集成。一方面,COPY table TO 'file.arrow' (FORMAT arrow)FROM 'file.arrow' 支持把表导出/导入为 Arrow 文件格式。另一方面,DuckDB 的 Python/其他语言接口支持把内存中的 Arrow Table 直接注册查询,由于两者都是列式内存布局,DuckDB 可以"零拷贝"地引用 Arrow 数据,不做逐列复制,从而避免序列化开销、提升跨系统(如 Pandas、PyArrow、Spark)的分析效率。这种集成让 DuckDB 成为 Arrow 生态中的高效分析引擎。

零拷贝的前提是内存布局兼容(均为列式、无符号化或人工编码)。DuckDB 直接复用 Arrow 的 buffer 作为自己的列输入,省去行列转换,这在数据科学管道中价值显著。

#
★★

15. SQLite 的 auto_vacuum(NONE/FULL/INCREMENTAL)与 freelist 页面回收机制的差异?

说明 SQLite 的 auto_vacuum 三种模式(NONE/FULL/INCREMENTAL)与 freelist 页面回收机制的差异?

  • auto_vacuum 模式
  • freelist 页缓存
  • 空间回收时机

SQLite 删除数据后释放的页会进入 freelist(空闲页列表)。auto_vacuum=NONE(默认):释放的页留在 freelist 中复用,数据库文件不自动缩小,除非手动 VACUUM。FULL:每个事务提交后自动把 freelist 页移到文件末尾并截断,文件即时缩小,但每次删除都有额外 IO。INCREMENTAL:需要手动调用 PRAGMA incremental_vacuum,按批次把 freelist 页回收并截断,兼顾空间回收与可控 IO。三者的取舍是"文件大小即时性"与"维护开销"之间的平衡。

NONE 用空间换性能(减少文件碎片、避免频繁截断),FULL 保证文件不膨胀但 IO 多,INCREMENTAL 把回收时机交给应用控制。Freelist 本身是复用关键,避免频繁扩展文件。

#
★★

16. SQLite 的 UPSERT(ON CONFLICT DO UPDATE/NOTHING)与 RETURNING 子句的语义?

说明 SQLite 的 UPSERT(ON CONFLICT DO UPDATE/NOTHING)与 RETURNING 子句的语义与用法?

  • ON CONFLICT 冲突处理
  • DO UPDATE / DO NOTHING
  • RETURNING 返回受影响行

SQLite 的 UPSERT 通过 INSERT ... ON CONFLICT (col) DO UPDATE SET ...DO NOTHING 实现。冲突目标(CONFLICT 目标列)指定唯一约束/主键;DO UPDATE 更新冲突行的指定列(可用 excluded. 引用本次插入值),DO NOTHING 则跳过冲突行。RETURNING 子句返回被插入或被更新的行(乃至所有受影响列),便于应用拿到新生成的 id 或更新后的值,省去二次查询。与 PostgreSQL 语义一致,但 SQLite 的 DO UPDATE 只更新命中的行,且 upsert 不触发级联一些行为需注意。

UPSERT 是"幂等写入"的利器,配合 RETURNING 可在一次语句里完成"插入或更新并返回结果",常见于数据同步、去重入库场景。

INSERT INTO users(id, name) VALUES(1, 'alice')
ON CONFLICT(id) DO UPDATE SET name = excluded.name
RETURNING id, name;
#
★★

17. SQLite 外键默认不启用(PRAGMA foreign_keys)的原因与启用后对 DELETE/UPDATE 级联的影响?

说明 SQLite 外键默认不启用(PRAGMA foreign_keys)的原因,以及启用后对 DELETE/UPDATE 级联行为的影响?

  • 外键约束默认关闭
  • PRAGMA foreign_keys 打开
  • 级联删除/更新(ON DELETE CASCADE)

SQLite 为保持向后兼容与性能,默认关闭外键约束执行(PRAGMA foreign_keys 默认 OFF)。原因是历史上外键是后加的,且校验外键会带来额外开销,若开启可能破坏旧应用的既有行为。每个连接需单独执行 PRAGMA foreign_keys = ON 来启用。启用后,外键声明中的 ON DELETE CASCADEON UPDATE CASCADESET NULL 等引用动作才会生效,删除/更新父表行时会按规则级联操作子表;同时违反外键的插入/更新会被拒绝。

外键约束与级联是数据完整性的一部分,但默认关闭意味着"用了才生效"。在启用外键且想用级联时,必须逐个连接开启 PRAGMA,并注意事务内执行顺序,否则会误以为约束未生效。

#
★★

18. DuckDB 的 JSON 处理,json_extract/json_transform 等函数与嵌套结构的查询与展开?

说明 DuckDB 的 JSON 处理能力,包括 json_extract、json_transform 等函数以及嵌套结构的查询与展开?

  • json_extract 与路径提取
  • json_transform/json deserialization
  • 嵌套结构展开(列表、struct)

DuckDB 提供完整的 JSON 支持。json_extract(json, '$.path') 用 JSONPath 提取值;json_transform/json_extract 可将 JSON 转换为 DuckDB 的强类型(struct/list)或按 schema 反序列化;json_objectjson_array 用于构造。对于嵌套结构,DuckDB 用 structlist 原生类型表示,可通过字段访问(.)与 unnest() 展开列表,或与 json_transform 把任意 JSON 映射到结构化类型后做列式分析。->/->> 运算符也提供便捷提取。

DuckDB 把 JSON 视为可导航、可结构化的数据,而非黑盒文本。通过 json_transform 一次性转换整个嵌套文档为类型化列,再配合 unnest 展开数组,能高效做嵌套文档的分析查询。

SELECT json_extract(doc, '$.user.name') AS name,
       s.item
FROM orders, unnest(json_extract(doc, '$.items')) AS s(item);
#
★★

19. SQLite 全文检索(FTS5)的倒排索引与中文分词(unicode61、trigram)的查询差异?

说明 SQLite 全文检索 FTS5 的倒排索引机制,以及 unicode61 与 trigram 分词器在中文查询上的差异?

  • FTS5 倒排索引
  • unicode61 / trigram 分词器
  • 中文分词与模糊匹配

FTS5 是 SQLite 的全文检索扩展,基于倒排索引:把文档按 token 分词,建立"词 → 文档列表"的映射,支持 MATCH 查询、短语匹配、前缀/后缀搜索与 BM25 相关度排序。分词器决定如何切分 token:unicode61 按 Unicode 字符类别切分(适合英文单词,对中文按字符切分,无法理解词边界),trigram 按连续 3 个字符切分 trigram,对中文无需词典即可做子串与模糊匹配,但索引更大。对中文,unicode61 无法做真正的"分词",trigram 则通过字符 n-gram 近似支持中文搜索与模糊查询。

中文无空格分词,倒排索引的 token 生成难度大。unicode61 逐字切分适合精确子串但与"词"语义不同;trigram 用 n-gram 避开词典,换取对中文的模糊/子串匹配能力,代价是索引膨胀与查询开销增加。

#
★★

20. DuckDB 的 Secret Manager 与 httpfs,S3/对象存储凭证的安全管理与访问控制?

说明 DuckDB 的 Secret Manager 与 httpfs 如何安全管理 S3/对象存储凭证并进行访问控制?

  • Secret Manager 凭证管理
  • httpfs 扩展
  • 凭证作用域与访问控制

DuckDB 的 httpfs 扩展支持访问 S3/HTTP 等对象存储,其凭证通过 Secret Manager 管理:CREATE SECRET 定义密钥(类型、访问密钥、region、endpoint 等),Secret 可指定 scope(作用域,如特定连接、数据库或文件路径前缀),实现凭证的局部可见性。凭证默认存储在内存或本地持久化位置,支持环境变量、配置重定向,避免在 SQL 中明文暴露密钥。通过 Secret 的作用域与权限控制,可以限制哪些查询能访问哪些存储,配合对象存储侧策略形成访问控制。

安全管理的关键是"凭证不落 SQL、不写死代码、按作用域隔离"。Secret Manager 让凭证可复用、可轮换、可限定范围,是 DuckDB 作为分析引擎安全访问云存储的基石。

CREATE SECRET my_s3 (TYPE S3, KEY_ID 'AKIA...', SECRET '...', REGION 'us-east-1');
SELECT * FROM read_parquet('s3://bucket/data/*.parquet');
#
★★

21. DuckDB 的内存模式(:memory:)与持久化文件模式在事务、性能与并发上的差异?

说明 DuckDB 的 :memory: 内存模式与持久化文件模式在事务、性能与并发上的差异?

  • 内存模式与文件模式
  • 事务持久性
  • 性能与并发差异

:memory: 模式把所有数据放在内存,不落盘,读写速度最快、无磁盘 IO,但进程退出即数据丢失,且事务不持久(崩溃丢失)。文件模式把数据持久化到磁盘文件,数据可跨进程会话保留,事务有持久性保证,但受磁盘 IO 制约,性能通常低于内存模式。并发上两者都受单进程写者限制(DuckDB 同一数据库文件同一时刻一个写进程),但内存模式无文件锁开销、切换更快;文件模式支持多进程只读共享。

选择取决于数据生命周期:内存模式适合临时分析、中间结果、快速原型;文件模式适合需要持久化与跨会话分析。两者事务语义一致,差别在持久化与 IO。

#
★★

22. SQLite 的 page_size 与 max_page_count 配置对存储空间与随机 IO 的影响?

说明 SQLite 的 page_size 与 max_page_count 配置对存储空间与随机 IO 的影响?

  • page_size 页大小
  • max_page_count 页数上限
  • 存储空间与随机 IO

SQLite 以页为单位读写,页大小(page_size,默认 4096 字节,可在建库时设置)影响 IO 与空间:页越大,单页可容纳更多行,B+Tree 树更矮、顺序扫描更少页,但随机访问单页传输的字节更多、缓存占用更大;页越小则碎片更少、缓存更细,但树更深、页数更多。max_page_count 限制数据库文件的最大页数,从而隐含文件大小上限,用于防止失控增长。设置需在建库前(page_size 须在首次写入前设置)且对已有库需 VACUUM 才能改变。

page_size 是存储与 IO 的权衡旋钮:小页利于随机小读但文件碎片多,大页利于顺序读与大块传输但随机 IO 浪费。max_page_count 是容量护栏,二者共同决定文件的物理布局。

#
★★

23. DuckDB 与 MotherDuck 云同步,本地缓存、增量同步与冲突处理机制?

说明 DuckDB 与 MotherDuck 云同步的机制,包括本地缓存、增量同步与冲突处理?

  • MotherDuck 云数据库
  • 本地缓存与增量同步
  • 冲突处理

MotherDuck 是 DuckDB 的云托管服务,让 DuckDB 能连接云端数据库。DuckDB 通过 ATTACH 'md:...' 连接 MotherDuck,本地会缓存云数据(缓存表/分片)以降低延迟与重复拉取。同步通常采用增量方式:只传输变更的数据块而非全量,结合 block 级别的缓存与版本管理。写冲突处理上,MotherDuck 提供一定的并发控制与事务语义,多写者场景下可能以版本/锁机制协调,冲突时需由应用或按策略解决。由于边缘与云端都可能写入,冲突处理是"分布式多写"的关键挑战。

云同步的价值是"本地飞的 DuckDB + 云端共享存储"。缓存命中减少网络 IO,增量同步减少带宽,但多写者与最终一致需要处理冲突,这是托管分布式 SQLite/分析存储的普遍难点。

#
★★

24. SQLite 的在线备份,sqlite3_backup API 与 VACUUM INTO 在一致性上的差异?

说明 SQLite 的在线备份 sqlite3_backup API 与 VACUUM INTO 在一致性上的差异?

  • sqlite3_backup API 在线备份
  • VACUUM INTO 生成备份
  • 一致性保证

sqlite3_backup API 提供在线备份:把源数据库内容逐页复制到目标数据库,整个过程在一致性快照下进行,源库可继续读写,备份结果相当于某个一致时间点的完整副本。VACUUM INTO 则是把当前数据库"整理"(重建)后写入新文件,生成一个紧凑、无碎片的备份文件,同样保证一致性。两者区别:sqlite3_backup 可在运行中增量推进、目标可以是任意连接、支持 WAL 模式;VACUUM INTO 一次性生成完整文件,且会重建(vacuum)索引与页布局,产出更紧凑但每次全量。都保证返回的是逻辑一致的数据。

一致性是关键——两者都保证备份是"某一时刻的逻辑一致视图",不因源库并发写入而损坏。选择上,需要持续在线且不阻塞时用 sqlite3_backup,需要简洁紧凑快照时用 VACUUM INTO。

#
★★

25. DuckDB 通过 httpfs 扩展读取 S3/HTTP 数据

说明 DuckDB 如何通过 httpfs 扩展读取 S3/HTTP 数据?

  • httpfs 扩展
  • S3/HTTP 数据源
  • 并行与谓词下推

DuckDB 的 httpfs 扩展提供对象存储(S3、GCS、Azure)与 HTTP(S) 文件系统的访问能力。安装加载后,可用 read_parquet/s3://...read_csv('https://...') 等函数直接读取远程数据,或通过 COPY FROM 导入。httpfs 支持 glob 通配符、并行读取多个对象/分片、基于 Range 请求的按需读取,并能配合 Parquet 的统计信息做谓词下推与列裁剪,减少网络传输。S3 访问需通过 Secret Manager 配置凭证。

httpfs 让 DuckDB 成为"不落地的数据湖查询引擎",把对象存储当作虚拟文件系统。并行 + Range 读取 + 下推是它高性能读远程列存的关键。

INSTALL httpfs; LOAD httpfs;
SELECT station, AVG(temperature)
FROM read_parquet('https://data.example.com/weather/*.parquet')
GROUP BY station;
#
★★

26. libSQL 是 SQLite 的 fork,扩展 HTTP wire protocol 与 async API

说明 libSQL 作为 SQLite fork 的扩展能力,特别是 HTTP wire protocol 与 async API?

  • libSQL 与 SQLite 关系
  • HTTP wire protocol
  • async API

libSQL 是 SQLite 的开放 fork(由 Turso 维护),在保持 SQLite 兼容性的同时扩展了服务端能力。它新增了 HTTP wire protocol,允许客户端通过 HTTP 协议与数据库交互,适用于 Web/边缘/受限环境,无需原生 socket 协议;同时提供 async API,支持异步非阻塞的数据库操作,便于在异步运行时(如 JavaScript/Node 等)中高效使用,避免阻塞事件循环。libSQL 还保留了嵌入式能力,并支持嵌入式副本、向量索引等扩展。

libSQL 的定位是"把 SQLite 变成既能嵌入式、又能服务化的数据库"。HTTP 协议降低接入门槛,async 提升并发吞吐,这些都是原版 SQLite 不具备的。

#
★★

27. Turso 基于 libSQL 提供托管分布式 SQLite 服务

说明 Turso 如何基于 libSQL 提供托管分布式 SQLite 服务?

  • Turso 服务架构
  • 分布式 SQLite
  • 多区域与嵌入式副本

Turso 是一个基于 libSQL(SQLite fork)的托管数据库服务,提供多区域的分布式 SQLite。它把 SQLite 数据库托管到云上,支持多区域副本(在每个区域放置可读副本),应用可通过 HTTP 或异步驱动访问,也可在边缘/客户端嵌入只读副本实现就近读取。Turso 通过 libSQL 的扩展能力(嵌入式复制、HTTP 协议)实现"分布式 SQLite":主库强一致、多区域读到最近副本,写入走主库或主可写副本。它面向边缘计算、无服务器与对低延迟敏感的 Web 应用。

Turso 解决了 SQLite 单机、单点的局限,把 SQLite 的简单与分布式的扩展结合。其核心是"嵌入式副本就近读 + 主库写 + 复制同步",在简单性与扩展性之间取得平衡。

#
★★

28. libSQL 支持 WebAssembly 与原生两种运行时

说明 libSQL 支持的 WebAssembly 与原生两种运行时的差异与适用场景?

  • 原生运行时
  • WebAssembly/WASM 运行时
  • 沙箱与部署场景

libSQL 提供两种运行时形态:原生(native)运行时,编译为机器码在服务器/嵌入式进程中直接运行,性能高、支持完整文件系统与并发;WebAssembly 运行时,把数据库编译为 WASM 运行在浏览器或 WASI 运行时中,受沙箱约束,通过 OPFS/IndexedDB 持久化,适合边缘、浏览器、无服务器环境。两种运行时共享同一套 SQL 与 API 语义,但 WASM 受沙箱限制(无直接文件系统/网络),通过 WASI 代理访问宿主资源。

双运行时让同一数据库能"上云、下边缘、进浏览器"。原生追求性能与功能,WASM 追求可移植与安全,选择取决于部署环境与资源约束。

#
★★

29. SQLite WASM 在浏览器中执行,依赖 OPFS(Origin Private File System)持久化

说明 SQLite WASM 在浏览器中的执行方式,以及如何依赖 OPFS 实现持久化?

  • SQLite WASM 浏览器执行
  • OPFS(Origin Private File System)
  • 浏览器持久化与沙箱

SQLite 可编译为 WASM 在浏览器中运行,成为纯前端数据库。由于浏览器沙箱不允许直接访问本地文件系统,SQLite 通过 VFS(虚拟文件系统)把文件操作映射到浏览器存储。OPFS(Origin Private File System)是浏览器为每个源(origin)提供的私有文件系统,支持快速、结构化并可持久化的文件访问,是 SQLite WASM 推荐的高性能持久化后端(逐页面/逐块读写,性能接近本地)。此外也支持 IndexedDB 作为后端。用户数据保存在浏览器本地,刷新/关闭后仍在,但受浏览器存储配额与清理策略约束。

浏览器沙箱 + OPFS 让 SQLite 能"在浏览器持久化",这是 PWA、本地优先(local-first)应用的数据基础。OPFS 相比 IndexedDB 更适合 SQLite 的页级随机读写。

#
★★

30. SQLite 通过 VFS 抽象文件系统,jswasm 模式使用 IndexedDB

说明 SQLite 通过 VFS 抽象文件系统,以及 jswasm 构建模式使用 IndexedDB 作为持久化后端?

  • VFS 抽象层
  • jswasm 构建
  • IndexedDB 持久化

SQLite 通过 VFS(Virtual File System)抽象层把文件 IO 与具体系统解耦,不同平台只需实现 VFS 接口即可替换文件系统行为。在 WASM/浏览器环境中,SQLite 的 VFS 被实现为访问浏览器存储:jswasm 构建(官方 WASM 构建脚本)提供基于 IndexedDB 的 VFS 后端,把数据库文件序列化存入 IndexedDB 对象,实现跨会话持久化。相比 OPFS 的页级访问,IndexedDB 以整文件/块方式存储,更简单但性能略低。VFS 抽象使同一 SQLite 内核可运行在本地、内存、OPFS、IndexedDB 等不同后端。

VFS 是 SQLite 可移植性的核心,也是它在浏览器中"伪装"文件系统的关键。jswasm 用 IndexedDB 提供持久化,application 侧则通过 VFS 选择后端,实现"同一个库、多种存储"。

#
★★

31. DuckDB 的统计信息(ANALYZE、min/max、字典)如何支撑优化器做 join 排序与过滤裁剪?

说明 DuckDB 的统计信息(ANALYZE、min/max、字典)如何支撑优化器进行 join 排序与过滤裁剪?

  • ANALYZE 统计收集
  • min/max 与字典统计
  • 优化器基于统计的决策

DuckDB 的优化器依赖统计信息做成本估算。ANALYZE 收集表/列的基数、min/max、null 比例、字典(distinct 值)等统计。优化器据此估算中间结果大小、选择度,从而决定 join 顺序(小表驱动大表、选择 join 策略)、过滤下推范围(通过 min/max 裁剪整块数据)、以及是否用 hash join 或 nested loop。例如某列 min/max 已知,过滤条件不满足时可直接跳过;字典统计帮助估算 distinct 数,影响聚合与 join 的基数假设。DuckDB 也会在执行时利用运行时统计做自适应优化。

统计信息是成本优化器的"眼睛"。没有统计,优化器只能靠默认假设,可能选错 join 顺序或策略。DuckDB 的列存 min/max 还能同时用于存储层面的 IO 裁剪。

#
★★

32. SQLite 只读访问的优化,URI mode=ro、PRAGMA query_only 与 immutable 参数的应用?

说明 SQLite 只读访问的几种优化方式:URI mode=ro、PRAGMA query_only 与 immutable 参数?

  • URI mode=ro 只读打开
  • PRAGMA query_only
  • immutable 参数

SQLite 提供多种只读约束:URI 模式 file:...?mode=ro 以只读方式打开数据库,任何写入都会报错;PRAGMA query_only = ON 在连接层面禁止写操作(INSERT/UPDATE/DELETE 及 DDL 被拒绝),但连接仍可能写日志;immutable=1 参数告诉 SQLite 数据库文件不会改变,可跳过锁与日志检查,适合只读、不可变的分发文件(如随应用打包的只读数据库),性能最优。三者按安全强度与性能区分:mode=ro 强制只读,query_only 仅禁写,immutable 假设文件不变以省去锁开销。

只读优化在"只读缓存、数据分发、只读快照"场景重要。immutable 最激进(跳过锁/WAL),适合确定不可变的文件;mode=ro 与 query_only 用于防止误写。

#
★★

33. DuckDB 的 EXPLAIN,Logical Plan 与 Physical Plan 的区别及优化器各阶段的作用?

说明 DuckDB 的 EXPLAIN 中 Logical Plan 与 Physical Plan 的区别,以及优化器各阶段的作用?

  • EXPLAIN 输出
  • Logical Plan vs Physical Plan
  • 优化器阶段(规则、下推、join 排序)

DuckDB 的 EXPLAIN 输出分为两层:Logical Plan 描述查询的逻辑步骤(扫描、连接、聚合的抽象操作),与存储和执行细节无关;Physical Plan 则是逻辑计划经过优化器优化后、映射到具体执行算子(如 hash join、vectorized scan、排序)的物理实现。优化器多个阶段负责:算子合并、常量折叠、谓词/投影下推、join 排序(基于统计)、列裁剪、选择连接策略等。PLAN 显示逻辑结构,优化后的物理计划决定实际执行路径。EXPLAIN ANALYZE 还会给出各算子实际耗时与行数。

Logical 回答"做什么",Physical 回答"怎么做"。优化器把逻辑计划逐步改写为更高效的物理计划,理解两层结构有助于诊断查询为何慢、算子取舍是否正确。

#
★★

34. SQLite 的锁级别(SHARED/RESERVED/PENDING/EXCLUSIVE)与 busy_timeout 的等待行为?

说明 SQLite 的锁级别(SHARED/RESERVED/PENDING/EXCLUSIVE)与 busy_timeout 的等待行为?

  • 锁级别体系
  • 锁升级与降级
  • busy_timeout 等待

SQLite 使用多级锁协调访问:SHARED 锁允许并发读;RESERVED 锁表示"将要写"但尚未真正写,此时仍允许其他读;写者一旦真正开始写,需把锁升级为 EXCLUSIVE 前先经过 PENDING 锁(PENDING 阻止新到 SHARED 锁,等待现有读者释放);最终 EXCLUSIVE 锁独占数据库完成写。整体是"锁逐步升级"的流程。busy_timeout 设置当获取锁失败时等待的毫秒数:若锁被占用,SQLite 会重试至超时,超时仍失败则返回 SQLITE_BUSY。在 WAL 模式下锁体系更简单(读不锁写)。

锁级别反映的是"读-写并发"的精细控制。busy_timeout 让应用在短暂锁冲突时静默等待而非立即报错,但过长的等待可能拖慢响应,需与写频繁程度匹配。

#
★★

35. DuckDB 的 CSV/JSON 自动模式推断(sniffer)与类型推断失败的处理策略?

说明 DuckDB 的 CSV/JSON 自动模式推断(sniffer)机制,以及类型推断失败时的处理策略?

  • CSV/JSON 自动推断
  • sniffer 抽样
  • 显式指定类型与容错

DuckDB 读取 CSV/JSON 时默认自动推断 schema(sniffer):通过采样文件头部若干行,推断每列的类型(如 INTEGER、DOUBLE、VARCHAR、DATE)与分隔符、编码、引号等格式参数。推断失败或不准确时(如某列混入不同类型、日期格式复杂、空值导致误判),可显式指定类型:用 read_csv(... , columns={'col':'INTEGER'})COPY ... WITH (FORMAT csv, HEADER true) 指定 schema;DuckDB 也提供 all_varchar=true 先全部按字符串读取再转换,或 auto_detect 关闭、union_by_name 处理异构 schema。类型强转失败时可用 TRY_CAST 或容错参数。

自动推断提高易用性,但它基于抽样,可能漏判或误判。稳健做法是:对关键列显式声明类型,采样推断失败时用 all_varchar + 手动 CAST 或 TRY_CAST 兜底,避免类型错误导致查询失败。

SELECT * FROM read_csv('data.csv', auto_detect=true, columns={'id':'INTEGER','name':'VARCHAR'});
#

36. DuckDB 的 Python API,register/replace 注册 DataFrame 与直接查询内存数据的方式?

说明 DuckDB 的 Python API 中 register/replace 注册 DataFrame 与直接查询内存数据的方式?

  • DuckDB Python 连接
  • register / replace 注册 DataFrame
  • 内存数据直接查询

DuckDB 的 Python API 提供 duckdb.connect() 创建连接,register(df, name) 把 Pandas DataFrame 注册为可查询的表,replace() 则覆盖同名已注册表(在 schema 变化时避免冲突)。注册后即可用 SQL 查询该 DataFrame,无需导入。此外 DuckDB 与 Arrow 深度集成,可直接查询 PyArrow Table、Polars DataFrame 等内存数据,实现零拷贝访问。Python 连接还支持 executefetchmany、字符串查询等。这让 Python 数据科学工作流能"用 SQL 分析内存数据"。

关键价值是"SQL 直接跑在内存数据上",避免 CSV/数据库往返。register 提供名字绑定,replace 处理同名覆盖,Arrow/Polars 零拷贝则进一步提升性能。

import duckdb
con = duckdb.connect()
con.register(df, 'tbl')
print(con.execute("SELECT * FROM tbl WHERE col > 10").fetchall())
#

37. DuckDB 的并发访问模型,多进程只读共享文件与单写者限制下的实践?

说明 DuckDB 的并发访问模型,特别是多进程只读共享文件与单写者限制下的实践?

  • 多进程只读共享
  • 单写者限制
  • 并发实践

DuckDB 的并发模型是"单写者、多读者":同一数据库文件同一时刻只允许一个进程写入,但多个进程可以同时以只读方式打开共享文件。读写都基于文件锁机制,写进程排他锁、读进程共享锁。实践中,若需要多个写入者,通常用"单写者 + 外部协调"(如队列、锁、或前置写入服务),或把数据分片/分库。只读分析场景(多个分析进程读同一数据文件)是 DuckDB 的常见用法,可以直接共享。要注意:并行写会因锁冲突报错,需避免。

该模型是嵌入式引擎的典型取舍:牺牲多写并发换取简单与性能。多进程只读共享对数据分析场景足够,写场景需通过架构(单写者)规避竞争。

#

38. SQLite 的表达式索引与部分索引(WHERE 子句)在查询优化中的应用?

说明 SQLite 的表达式索引与部分索引(含 WHERE 子句)在查询优化中的应用?

  • 表达式索引
  • 部分索引(WHERE)
  • 查询优化

SQLite 支持表达式索引:CREATE INDEX idx ON t(lower(name)),对表达式计算结果建索引,当查询 WHERE 中使用了相同表达式时可直接命中,避免对全表逐行计算。部分索引(partial index):CREATE INDEX idx ON t(col) WHERE status='active',只对满足条件的行建索引,索引更小、更新开销更低,适合"只查询活跃子集"或"稀疏过滤"场景。实际中二者结合(部分 + 表达式)可精准覆盖高频查询模式。不过表达式索引要求查询表达式与索引表达式完全一致才能触发。

表达式索引把"函数调用"变成可索引的比较,部分索引用最小索引覆盖高频子集,两者都减少 IO 与维护成本。关键是查询必须以与索引定义一致的表达式出现。

CREATE INDEX idx_lower_name ON t(lower(name));
CREATE INDEX idx_active ON t(id) WHERE status='active';
SELECT * FROM t WHERE lower(name)='alice';
#

39. DuckDB 的 SQL UDF(CREATE FUNCTION)与宏(CREATE MACRO)在复用分析逻辑时的差异?

说明 DuckDB 的 SQL UDF(CREATE FUNCTION)与宏(CREATE MACRO)在复用分析逻辑时的差异?

  • CREATE FUNCTION UDF
  • CREATE MACRO
  • 复用与性能

DuckDB 的 CREATE FUNCTION 可创建标量 UDF 或表函数(返回表),逻辑以 SQL 表达式/语句定义,作为真正的函数被调用,可复用复杂的分析逻辑。CREATE MACRO 则是"宏":本质是 SQL 表达式的模板替换/常量表达式,调用时展开为表达式,通常用于把常用表达式(如 avg(x)/stddev(x))封装成简写。区别:UDF 更像独立函数(可返回表、可递归),宏更轻量、是内联的表达式替换,性能上宏展开后无额外调用开销;UDF 在 SQL 层面内联,但若有复杂逻辑也应评估。两者都避免重复书写相同逻辑。

宏是"语法糖/表达式简写",UDF 是"真正的函数"。简单标量表达式用宏,复杂逻辑/返回表用 UDF。选择取决于逻辑复杂度与是否需要作为函数签名复用。

#

40. SQLite 的临时表(TEMP)与 WITHOUT ROWID 表的语义与适用场景?

说明 SQLite 的临时表(TEMP)与 WITHOUT ROWID 表的语义与适用场景?

  • 临时表(TEMP)
  • WITHOUT ROWID 表
  • 适用场景

临时表(CREATE TEMP TABLE)只存在于当前连接/会话,会话结束自动删除,不写入磁盘(或写临时文件),用于会话内中间数据、避免污染主库。WITHOUT ROWID 表是一种不维护隐式 rowid 的表,必须以显式主键作为 B+Tree 的 key,且主键必须是 INTEGER PRIMARY KEY(或其他类型)作为聚簇索引;它去掉了 rowid 列,减少存储、索引更紧凑,适合"有自然主键、需要按主键快速查找、行通常全量读取"的场景。代价是删除/更新需按主键,因此适合主键唯一、无频繁重排的表。

临时表管理会话生命周期,WITHOUT ROWID 优化存储与主键查找。WITHOUT ROWID 表 B+Tree 直接以主键为 key,无额外 rowid 索引,适合主键即查询键的表。

#

41. DuckDB 的查询内存控制,PRAGMA memory_limit 与外部排序/聚合落盘(spill)如何避免 OOM?

说明 DuckDB 的查询内存控制机制,包括 PRAGMA memory_limit 与外部排序/聚合落盘(spill)如何避免 OOM?

  • memory_limit 内存上限
  • 外部排序/聚合 spill
  • 内存预算与 OOM 防护

DuckDB 通过 PRAGMA memory_limit 设置查询可用的内存上限,超过上限的算子(如排序、聚合、hash join)会把中间结果"spill"(落盘)到临时文件,从而避免 OOM。DuckDB 使用全局内存管理器按算子分配内存预算,当某算子超过预算时触发 spill 到磁盘并分段处理。这样即便数据量远超内存,也能以牺牲一些性能为代价完成查询。用户可通过 PRAGMA memory_limit='4GB' 或线程数限制来控制内存占用,生产上常配合 threadstemp_directory 使用。

"允许落盘"是 DuckDB 大查询不崩溃的关键。与 OOM 一刀切不同,spill 提供优雅降级:能跑就慢点跑。内存预算 + 落盘使查询在受限环境更稳健。

PRAGMA memory_limit='2GB';
PRAGMA temp_directory='/tmp/duckdb_spill';
#

42. SQLite 的虚拟表机制(CREATE VIRTUAL TABLE、自定义 create_module)如何扩展存储与索引?

说明 SQLite 的虚拟表机制(CREATE VIRTUAL TABLE、自定义 create_module)如何扩展存储与索引?

  • 虚拟表机制
  • 自定义 create_module
  • 扩展存储与索引

虚拟表(virtual table)允许把"外部/自定义数据结构"当作 SQLite 表来查询,提供标准 CREATE VIRTUAL TABLE 建表。它通过实现一组 C 回调(xCreate、xBestIndex、xOpen、xFilter、xNext 等)组成"模块"(module),由 sqlite3_create_module 注册后再用 CREATE VIRTUAL TABLE t USING modname(...) 实例化。这样可把内存结构、外部存储、全文索引(FTS5 即虚拟表)、稀疏向量等映射为表,并实现自定义索引(xBestIndex 让优化器决定如何利用底层索引)。虚拟表让 SQLite 的存储与索引能力可无限扩展。

虚拟表是 SQLite 的"外部存储适配器"。xBestIndex 向优化器声明可用约束,xFilter 执行过滤,从而优化器能把谓词下推到自定义后端。FTS5、JSON、矢量等扩展都基于此机制。

#

43. DuckDB 的 VIEW 与 CTE 在分析查询中的复用与性能差异(是否物化)?

说明 DuckDB 中 VIEW 与 CTE 在分析查询中的复用逻辑与性能差异(是否物化)?

  • VIEW 与 CTE 定义
  • 物化与否
  • 复用与内联

DuckDB 的 VIEW 是持久化的命名查询(存于 catalog),可被多个查询复用;CTE(WITH 子句)是单查询内的临时命名子查询。两者都默认"非物化"(inline):DuckDB 会把 CTE/VIEW 的 SQL 内联到主查询中,由优化器统一优化,可能被多次展开。与某些默认物化 CTE 的数据库不同,DuckDB 的 CTE 通常不强制物化,意味着同一 CTE 被引用多次时可能重复执行,除非优化器判断物化更优。因此分析高复用逻辑时,若 CTE 很重且被多次引用,可考虑显式物化(如创建临时表)以复用结果。

"是否物化"决定了复用是"共享结果"还是"重复计算"。DuckDB 默认内联,利于下推与优化,但重 CTE 多引用时可能重复计算;业务可在正确性与性能间用临时表做显式物化。