基准测试套件
Goose 提供了完善的基准测试套件。 当你做出可能影响性能的改动时,务必运行这些基准测试以发现潜在性能回退。
快速开始
在 Goose 仓库中构建基准测试套件:
BUILD_BENCHMARK=1 BUILD_EXTENSIONS='tpch' make
列出基准测试
列出全部可用基准测试:
build/release/benchmark/benchmark_runner --list
运行基准测试
运行单个基准测试
运行单个基准测试可执行:
build/release/benchmark/benchmark_runner benchmark/micro/nulls/no_nulls_addition.benchmark
输出会以 CSV 形式打印到 stdout,格式如下:
name run timing
benchmark/micro/nulls/no_nulls_addition.benchmark 1 0.121234
benchmark/micro/nulls/no_nulls_addition.benchmark 2 0.121702
benchmark/micro/nulls/no_nulls_addition.benchmark 3 0.122948
benchmark/micro/nulls/no_nulls_addition.benchmark 4 0.122534
benchmark/micro/nulls/no_nulls_addition.benchmark 5 0.124102
你也可以通过 --out 指定输出文件。该文件只会写入耗时数据(按换行分隔)。
build/release/benchmark/benchmark_runner benchmark/micro/nulls/no_nulls_addition.benchmark --out=timings.out
文件内容示例:
0.182472
0.185027
0.184163
0.185281
0.182948
使用正则运行多个基准测试
你也可以通过正则表达式指定要运行的基准测试。
注意 shell 对部分正则字符的展开(如 * 常会被 shell 展开),因此需要正确引用或转义。
build/release/benchmark/benchmark_runner "benchmark/micro/nulls/.*"
运行全部基准测试
不传任何参数时将运行全部基准测试。
build/release/benchmark/benchmark_runner
其他选项
--info 可输出该基准测试的额外信息。
build/release/benchmark/benchmark_runner benchmark/micro/nulls/no_nulls_addition.benchmark --info
display_name:NULL Addition (no nulls)
group:micro
subgroup:nulls
--query 会打印该基准测试实际执行的查询。
SELECT min(i + 1) FROM integers;
--profile 会输出查询树。
创建基准测试
许多开发工作都与性能相关。 在其他测试之外加入基准测试,不仅能验证性能优化,也能防止该功能未来出现性能回退。
基准测试示例
下面以 FILL 窗口函数为例说明如何创建 benchmark 文件。
(FILL 会在有序分区内对缺失值做线性插值。)
benchmark 文件与单元测试文件类似,头部格式也相同。
# name: benchmark/micro/window/window_fill.benchmark
# description: Measure the performance of FILL
# group: [window]
可使用 make format-head 确保头部结构符合预期并避免 tidy 检查报错。
头部下方是一组描述 benchmark 的关键字。
name FillPerformance
group micro
subgroup window
有些 benchmark 只运行一条查询,但更常见的是通过 argument 关键字对 benchmark 做参数化。
这样可用不同配置(如数据规模)重复运行。
FILL 示例中有三个参数:
argument sf 10
argument errors 0.1
argument keys 4
在 FILL 中分别表示:
- scale factor(每个分区的百万行数)
- error rate(缺失值占比)
- 分区数量
benchmark 通常在运行查询前需要准备数据。
数据准备写在 benchmark 文件的 load 段。
FILL 示例中我们使用参数与随机数生成器构造数据表。
load
select setseed(0.8675309);
create or replace table data as (
select
k::TINYINT as k,
(case when random() > ${errors} then m - 1704067200000 else null end) as v,
m,
from range(1704067200000, 1704067200000 + ${sf} * 1_000_000 * 10, 10) times(m)
cross join range(${keys}) keys(k)
);
查询中会展开 argument 参数,方式类似单元测试里 foreach 的值展开。
注意 load 段可以包含多条 SQL 语句。
数据准备完毕后,就可以在 run 段定义要测的查询。
其限制与单元测试相同(例如不能有空行等)。
在 FILL 基准中,我们要找出插值失败的位置:
run
SELECT
m,
k,
fill(v) OVER (PARTITION BY k ORDER BY m) as v
FROM
data
qualify v <> m - 1704067200000;
如果插值正确,则无论 scale 如何都不应有输出。
我们通过最后的 result 子句进行校验,
其语法与单元测试一致:
result III
通过“无输出行”这一断言,我们既能验证查询正确性,也能评估其性能。
顶层 benchmark/ 目录下还有许多其他示例,
建议查看以了解更多技巧。