TL;DR
- DuckDB 大量使用 template,但目的通常很实际。
- 数据库执行引擎有很多“形状相同、物理类型不同”的 primitive。
- Template 让源码保持紧凑,同时让编译器生成直接的 typed code。
数据库里的问题
执行引擎会反复需要这些操作:
- integer comparison
- decimal arithmetic
- string operation
- aggregate update
- hash probe
- vectorized unary/binary operation
算法形状经常相同,变化的是物理类型。
如果每种组合都手写,代码会大量重复。正确性也更难保证,因为每份手工复制的代码都可能慢慢漂移。
Template 带来的东西
Template 可以表达这种模式:
same algorithm shape
different physical type
different operation
编译器再为实际类型生成特化代码。这对数据库很重要,因为很多 primitive 在 tight loop 里运行。很小的抽象成本也可能被放大。
这也是 if constexpr 有用的地方。普通 if 要求两个分支都能通过类型检查。if constexpr 可以让编译器丢掉当前类型不需要的分支。
这样一个 template 就能覆盖 signed/unsigned、不同 aggregate state、不同 vector operation,而不需要一堆手工 specialization。
Template 不能解决什么
Template 不能替代好的执行布局。
DuckDB 仍然需要 vector、validity mask、selection vector、string heap、hash table payload layout 和 memory accounting。Template 只是帮助表达 typed operation,不能把糟糕的物理布局变快。
Template 也有成本:
- 编译时间更长
- 生成代码可能更大
- 错误信息更难读
- ABI 和模块边界需要更小心
所以合理的使用范围很窄:primitive、type dispatch,以及真的需要 specialization 的 hot typed kernel。
边界
一个简单说法是:
Template 不是数据库引擎。
Template 是写数据库引擎内部 typed primitive 的工具。
对 DuckDB 来说,这是合理的 C++ 取舍。