kryonix此PR将CALL dbgen(…)接入进度条和ETA(预计剩余时间)基础设施,并显著提升执行速度,尤其是在较大规模因子(scale factor)和持久化数据库中。

此前,TPC-H生成可能在长时间内没有任何有意义的进度反馈。DuckDB已有CLI进度条支持,但TPC-H的dbgen路径并未使用它。此PR将dbgen接入进度系统,并同时跟踪已生成工作和已刷盘工作,使得进度条在存储阶段也能持续前进,而不是从部分进度直接跳转到完成。

在处理进度报告时,ETA行为也需要关注。之前的终端ETA使用了卡尔曼估计器,这对于相对平滑的进度信号效果较好。但TPC-H生成具有突发性:并行工作线程以不均等的时间完成数据块,持久化存储引入了刷盘阶段,并且进度可能以较大步长到达。这导致ETA对最新样本反应过度并剧烈跳动。

此PR用更简单的估计器替换了终端ETA逻辑:

  • 使用已耗进度的稳定基线,
  • 使用最近观察到的进度速率作为修正,
  • 对修正进行限幅,使得短时突发不会主导估计值,
  • 平滑预测的完成时间戳,
  • 允许后续估计值逐渐向外移动,而不是向上跳跃。

结果虽然不那么“聪明”,但更具可预测性:ETA仍然会在工作负载速度变化时进行调整,但不再随着每次进度更新而剧烈摆动。不过,我对这个改动并不执着,我们也可以直接恢复到之前的方式。

此PR更大部分重写了TPC-H dbgen的热路径追加逻辑。旧实现首先生成DBGEN行结构体,然后将这些值复制到DuckDB向量中。这带来了额外的行物化、额外的字符串处理以及可避免的日期格式化/解析工作。

新路径直接生成到DuckDB数据块中。具体而言,它:

  • 直接将TPC-H日期偏移量写为DuckDB日期,
  • 避免中间使用order_t、line_t、part_t等追加结构体,
  • 避免重复计算分布字符串长度,
  • 在安全的情况下直接引用稳定的DBGEN分布/文本池字符串,
  • 仅在DBGEN可能修改的值上保留可写的向量自有字符串存储,
  • 调整了并行生成的粒度,
  • 更早地刷新持久化追加状态,以保持内存使用受控。

最终结果是运行时大幅提升:

模式 查询 修改前 修改后 加速比
内存模式 dbgen(sf=1) 1.249s 0.259s 4.8倍
内存模式 dbgen(sf=10) 12.818s 1.274s 10.1倍
持久化模式 dbgen(sf=10) 46.752s 4.159s 11.2倍

在20GB内存限制下,SF 1000现在大约在470秒内运行完成。我不愿意等待旧实现完成,但可以肯定它会慢得多。

底层重写的主要实际收益是:减少了中间工作、减少了拷贝、减少了字符串/日期转换开销,并且对存储追加路径的压力大大降低。

在amd 8845主机 windows实际测试

C:\d>duckdb0712
DuckDB v1.6.0-dev10612 (Development Version, 2009475939)
Enter ".help" for usage hints.
memory D load tpch;
memory D .timer on
memory D call dbgen(sf=3);
Run Time (s): real 2.478 user 15.296875 sys 1.906250
memory D .exit

C:\d>duckdb154
DuckDB v1.5.4 (Variegata)
Enter ".help" for usage hints.
memory D install tpch;
memory D .timer on
memory D call dbgen(sf=3);
┌─────────┐
│ Success │
│ boolean │
└─────────┘
  0 rows
Run Time (s): real 7.573 user 26.296875 sys 3.343750
memory D .exit
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐