TL;DR
- DuckDB 和 PostgreSQL 都是数据库系统,但编程模型差异很大。
- DuckDB 更自然地使用 C++ ownership、RAII、exception 和 inheritance。
- PostgreSQL 使用
MemoryContext、ereport/longjmp和NodeTag。
简短对比
| 维度 | DuckDB | PostgreSQL |
|---|---|---|
| 内存管理 | smart pointer + RAII | MemoryContext |
| error handling | try/catch | longjmp |
| 多态表达 | inheritance | node + tag |
这不是谁先进、谁落后的问题。它们来自不同语言,也来自不同工程历史。
Ownership 和生命周期
在 DuckDB 里,logical operator、physical operator、expression、catalog entry 经常是 C++ class。子对象通常由 unique_ptr 持有。
这很适合树状结构:
父节点拥有子节点
父节点销毁
子节点跟着销毁
RAII 把这个思路扩展到内存之外。数据库系统里有 file handle、lock、buffer pin、temporary state、transaction-local object。RAII 让资源释放和对象生命周期绑定。
PostgreSQL 不一样。很多对象分配在 MemoryContext 里。生命周期由 reset/delete 整个 context 管理,而不是靠每个对象析构。
Error handling
DuckDB 使用 C++ exception。parser、binder、optimizer、executor 遇到错误时可以抛异常,上层捕获后转成用户可见错误。
PostgreSQL 使用 ereport 和 longjmp。这和 MemoryContext 配合很好,因为错误跳出后可以清理一整块内存区域。
C++ exception 和 RAII 配合自然,因为栈展开时对象会析构。但 exception 不能变成普通控制流。数据库 hot path 不应该用 exception 表达每行数据上的正常分支。
Runtime type
DuckDB 可以用 C++ inheritance 表达 expression、operator、function data。行为可以挂在对象上。
PostgreSQL 更常见的是 Node 加 NodeTag。运行时检查 tag,再 cast 到具体结构。
C++ inheritance 的局部类型结构更强,但 virtual call、对象布局和模块边界都要小心。
NodeTag 的布局直接,适合 C,但类型安全更多依赖约定。
边界
重点不是 DuckDB “更 C++”。重点是数据库系统选择的语言模型会塑造运行时模型。
DuckDB 关注对象 ownership 和析构。PostgreSQL 关注区域生命周期和显式 tag。两条路线都自洽。