
DuckDB 简介
最近发现了一个适合深入学习的开源分析型数据库——DuckDB[1]。简单说,DuckDB 是一个 OLAP[2](列存)版本的 SQLite[3]。
作为了一个学习样例,DuckDB 具有以下优点:
DuckDB 没有外部依赖,所以编译、链接、运行都可以一气呵成,非常简单。 代码不算多,除去测试代码,大概 13~14w 行,并且代码质量不错。 麻雀虽小,五脏俱全。并且 DuckDB 遵循教科书上的经典模块设计,相对容易看懂。 DuckDB 集成了 OLAP 领域的各种知识,它的各种设计、实现都可以找到参考论文,方便学习。
对比 LevelDB
之前也写过一系列 LevelDB 源码解析的文章。
代码量上,LevelDB 大概也就 2w 行,比 DuckDB 少很多。
功能上,LevelDB 只是一个简单的 key-value 存储。而 DuckDB 则是一个完成的数据库——SQL Parser、Optimizer、Execution Engine、Transaction、Storage 一个不少。
DuckDB 的模块介绍
SQL Parser
DuckDB 的 SQL parser[4] 是从 Postgres 的 libpg_query [5]精简而来的。由于 Postgres 是 C 语言写的,通过这个 SQL parser,我们会得到一个 C 语言结构体表示的 parse tree。DuckDB 会将其转换成自己内部的 C++ 对象。
Logical Planner
Logical planner[6] 由 binder 和 plan generator 两部分组成。Binder 将 parse tree 与 schema 的信息(列名、类型等)绑定起来。Schema 信息保存在 catalog[7]。Plan generator 将 parse tree 转换成一颗逻辑查询操作符(scan, filter, project 等)树。
Optimizer
DuckDB 实现了基于规则(rule-based)和基于代价(cost-based)的优化器。Optimizer[8] 的主要任务是优化 SQL,它将前面 logical planner 生成的 logical plan 转换成一个等价但执行代价更小的 logical plan。常见的优化方式有谓词下推(predicate pushdown)、表达式重写(expression rewriting)、调整 join 顺序(join ordering)等。
Physical Planner 和 Execution Engine
Physical planner 和 execution engine 的代码都在 execution [9]目录下。Physical planner 将 Logical plan 转换成 physical plan。Physical plan 是一个真正可以执行的物理计划。DuckDB 实现了一个向量化(vectorized)的解释型执行引擎。向量化可以利用 CPU 提供的 SIMD 指令加速计算。DuckDB 采用 SQL 的解释执行,而没有采用 SQL 的编译执行,原因是编译执行需要依赖编译组件,比如 LLVM,这会导致 DuckDB 的体积膨胀不少。
Transaction and Concurrency Control
DuckDB 支持 Serializable 的事务隔离。事务相关的代码在 transaction [10]目录下。
Storage
Storage [11]是 DuckDB 的列式存储引擎,处于整个 DuckDB 架构的最底层,负责提供数据的高效读写。
编译运行
DuckDB 的下载和编译很简单:
git clone https://github.com/duckdb/duckdb
cd duckdb
BUILD_BENCHMARK=1 BUILD_TPCH=1 make
编译完成后,我们可以得到一个 DuckDB 的二进制库+头文件。另外,我们得到一个 benchmark 程序,可以用来测试 DuckDB 的性能。
# 列出所支持的 benchmark
build/release/benchmark/benchmark_runner --list
# 运行指定的一个 benchmark
build/release/benchmark/benchmark_runner benchmark/tpch/sf1/q01.benchmark
# 运行某个目录下的 benchmark
build/release/benchmark/benchmark_runner 'benchmark/tpch/sf1/.*'
# 运行所有 benchmark
build/release/benchmark/benchmark_runner
关于 benchmark_runner 的更多功能,可以参考官方文档[12]。
参考资料
DuckDB: https://duckdb.org/
[2]OLAP: https://en.wikipedia.org/wiki/Online_analytical_processing
[3]SQLite: https://www.sqlite.org/index.html
[4]SQL parser: https://github.com/duckdb/duckdb/tree/v0.2.6/src/parser
[5]libpg_query : https://github.com/lfittl/libpg_query
[6]Logical planner: https://github.com/duckdb/duckdb/tree/v0.2.6/src/planner
[7]catalog: https://github.com/duckdb/duckdb/tree/v0.2.6/src/catalog
[8]Optimizer: https://github.com/duckdb/duckdb/tree/v0.2.6/src/optimizer
[9]execution : https://github.com/duckdb/duckdb/tree/v0.2.6/src/execution
[10]transaction : https://github.com/duckdb/duckdb/tree/v0.2.6/src/transaction
[11]Storage : https://github.com/duckdb/duckdb/tree/v0.2.6/src/storage
[12]官方文档: https://github.com/duckdb/duckdb/blob/v0.2.6/benchmark/README.md




