返回

ClickHouse 在 NVIDIA Vera CPU 上跑分登顶

RSS ClickHouse Blog AI 逐段翻译 发布 2026-10-21 21:13 收录于 10-22

有效阅读仅保存在当前浏览器,用于「为你」推荐;暂停或清除记录。

DataHot 速览

ClickHouse 团队在 NVIDIA 早期访问的 Vera CPU 平台上运行标准版 ClickHouse 与 ClickBench,未做针对性优化便登顶 ClickBench 硬件排行榜,且优势明显。Vera 双路系统提供 88 个 Arm-v9.2 兼容核心/路,共 176 核、352 线程,最大内存带宽 1.0-1.2 TB/s。文章还用过滤、聚合、连接三个微基准展示 ClickHouse 在 176 核上接近线性扩展。核心挑战不在硬件规格,而在数据库能否随核心数、缓存和带宽同步扩展。

为什么值得关注:这是数据库引擎在新硬件平台上的第一方性能实测,涉及 ClickBench 排名、176 核扩展性与实时分析负载,对评估分析型数据库硬件选型和性能边界有直接参考价值。

本文目录 6 节
  1. 表设置
  2. 微基准测试 1:过滤求值
  3. 微基准测试 2:聚合
  4. 微基准测试 3:连接
  5. 附加内容:SIMD 向量化
  6. 总结

译文

AI 逐段翻译

ClickHouse 的工程师们对性能有着执着的追求。每一次发布,我们都会寻找新方法,让 ClickHouse 在底层硬件上运行得更快、扩展得更好。当 NVIDIA 最近向我们提供了一台即将推出的 Vera CPU 平台的早期访问服务器时,我们做了显而易见的事:在上面运行 ClickBench,这是我们广受欢迎的分析基准测试。我们使用了网站上的标准 ClickHouse 二进制文件,没有专门针对 NVIDIA Vera 在数据库中进行任何优化或定制。结果不言自明:

NVIDIA Vera 以巨大优势直接登顶 ClickBench 硬件排行榜。

任何数据库工程师都会承认,Vera 是一个真正令人印象深刻的平台。它配备 88 个 NVIDIA Olympus 核心,完全兼容 Arm-v9.2。在双路系统中,得益于 NVIDIA Spatial Multithreading,总共拥有 176 个核心和 352 个硬件线程。每个核心可访问 96/64 kB 的 L1 数据/指令缓存、2 MB 的 L2 缓存和 164 MB 的共享 L3 缓存。最大内存带宽范围为 1.0 TB/s 至 1.2 TB/s,具体取决于系统中的 DRAM 容量。

你可能会说,更多的 CPU 核心、更多的缓存和更高的内存带宽自然会让任何基准测试运行得更快。虽然这有一定的道理,但真正的挑战在于让数据库性能随机器资源线性扩展。基本上:如果一台机器的性能翻倍,即 CPU 核心数翻倍、缓存翻倍、内存带宽翻倍等等,人们会期望查询运行速度也翻倍,而不只是快不到两倍。数据在磁盘上的组织方式、在内存中的表示方式以及处理方式——所有这些都会影响数据库的扩展能力。如果没有在每一层进行精心的工程设计,数据库将无法利用 Vera 庞大的核心数量和内存带宽,可能会让性能得不到充分发挥。

更强大的硬件有助于处理实时分析、数据仓库、可观测性和机器学习中新的数据和计算密集型用例。虽然传统上大多数查询是由仪表板(例如 Grafana、Superset)或 BI 工具(例如 Tableau 和 Looker)生成的,但我们越来越多地看到 ClickHouse Cloud 中的智能体自主回答数据问题。从数据库的角度来看,智能体查询具有三个特征:第一,它们本质上比常规查询更加“即席”,例如,它们可以具有复杂的形状,并且查询之间也会发生显著变化。第二,它们在不固定的时间到达,并且经常是突发性的。第三,大量智能体查询通常并行运行,因为智能体会生成自身也并行运行的子智能体。

我想在 Vera 上测试 ClickHouse 的可扩展性,因此我开发了三个微基准测试,模拟大多数常规查询和基于智能体的查询中常见的基本数据库操作。

  1. 过滤求值(SQL WHERE 子句)、
  2. 聚合(SQL GROUP BY 子句)以及
  3. 连接(SQL JOIN 子句)。

合成数据集应完全存储在内存中,这样磁盘 I/O(对象存储或本地 SSD)就不会构成人为瓶颈。幸运的是,ClickHouse 提供了Memory 表引擎专门用于此目的。ClickHouse 的查询处理层与其存储层完全解耦。假设存储带宽足够,基准测试结果可以转化为MergeTree表中的常规表现,无论是在ClickHouse Cloud还是ClickHouse 开源版中。

表设置

我们的测试表由单列组成,包含 625 亿个随机字符串,每个字符串长度在 5 到 10 个 ASCII 字符之间。表大小恰好为 1 TB。字符串以原始形式存储,未压缩(Memory 表引擎中压缩是可选的)。

1CREATE TABLE default.strings2(3    `s` String4)5ENGINE = Memory;67INSERT INTO strings SELECT randomPrintableASCII(5+ (rand() %6))8FROM numbers_mt(62500000000);

微基准测试 1:过滤求值

我运行的第一个微基准测试是一个简单的 LIKE 查询:

1SELECTcount()2FROM strings3WHERE s LIKE'%ab%';  -- how many strings contain sub-string ‘ab’

我使用不同的线程数(设置max_threads)测量了查询运行时间:

max_threads时间加速比效率
150.44 秒1.00x100.00%
413.19 秒3.82x95.60%
163.25 秒15.52x97.00%
641.23 秒41.01x64.08%
2561.11 秒45.44x17.75%

“时间”是运行查询的时间。“加速比”指定了与max_threads = 1相比,查询运行时间快了多少。“效率”是观察到的加速比与预期加速比的比值。例如,使用 32 个线程时,预期加速比为 32x。较低的加速比意味着效率低于 100%。

运行时间随查询线程数的增加而成比例减少……直到在 64 线程处遇到瓶颈。将线程数进一步增加到 256 并没有带来显著的额外加速。这种行为通常表明查询是 I/O 受限的,意味着核心处理数据的速度快于内存总线从 DRAM 读取或写入数据的速度。我们可以通过将总数据量(1 TB)除以查询执行时间来快速验证。

max_threads时间加速比效率吞吐量
150.44 秒1.00x100.00%19.83 GB/s
413.19 秒3.82x95.60%75.82 GB/s
163.25 秒15.52x97.00%307.69 GB/s
641.23 秒41.01x64.08%813.01 GB/s
2561.11 秒45.44x17.75%900.90 GB/s

确实,当查询停止扩展时,内存 I/O 为 813 GB/s(64 核),分别为 900 GB/s(256 核)。这个数值大致对应于 Vera 系统的物理内存带宽。这表明查询受内存限制——增加更多核心不会进一步加速它。

为了确保所有 CPU 资源在此限制之外也能被充分利用,我修改了查询,使其更加 CPU 密集:

1SELECTcount()2FROM strings3WHEREmatch(s, '[0-9][a-z][A-Z]'); -- how many strings match this regular expression?

之前的查询执行的是简单的子字符串搜索,而这个查询会对表中的每个字符串求值一个开销高昂的正则表达式。以下是结果:

max_threads时间加速比效率
11209.71.00100.00%
25982.02101.15%
4302.93.9999.84%
8150.98.02100.21%
1675.516.02100.14%
3237.832.00100.01%
6419.163.3498.96%
1289.8123.4496.44%
1767.4163.4792.88%
2565.6216.0284.38%
3525.3228.2564.84%

现在的执行时间几乎完美地随 CPU 核心数扩展。嗯,几乎总是如此……从 176 核(Vera 机器中物理核心的数量)开始,效率开始逐渐下降。超过这个核心数后,更多的软件线程由逻辑硬件线程而非物理硬件线程来服务。逻辑硬件线程(或 SMT 线程)与其他逻辑硬件线程共享物理核心。虽然逻辑硬件线程非常适合掩盖停顿,例如缓存缺失、分支预测错误或远程数据访问,但对于像过滤查询这样的计算密集型工作负载,它只能提供有限的帮助(例如 10-30% 的加速)。这正是我们在这里观察到的现象。

查询处理以显而易见的方式并行化:ClickHouse 将表分割成 352 个大小相等的虚拟块,然后同时对这些块进行过滤。这可以在 EXPLAIN PIPELINE 输出中看到:

1EXPLAIN PIPELINE2SELECTcount()3FROM strings4WHEREmatch(s, '[0-9][a-z][A-Z]')5SETTINGS max_threads =352;
1┌─explain───────────────────────────┐2│ (Expression)                      │3│ ExpressionTransform               │4│   (Aggregating)                   │5│   Resize 352 → 1                  │6│     AggregatingTransform × 352    │7│       (Expression)                │8│       ExpressionTransform × 352   │9│         (Filter)                  │10│         FilterTransform × 352     │11│           (ReadFromMemoryStorage) │12└───────────────────────────────────┘

不详细解释计划算子,x 352 在每个算子后面表示 352 个虚拟表块被并行处理。最后的 Resize 算子将 352 个部分结果合并为最终结果。

微基准测试 2:聚合

接下来,我测试了一个聚合查询:

1SELECT ascii(s) AS first_char, count(), sum(sipHash64(s))2FROM strings3GROUPBY first_char;

该查询按字符串的第一个字符分组(即 255 个分组),并返回每个分组的大小以及每个字符串的 (sip)hash 值之和。255 个分组是数据库工程师所说的“低基数”聚合。高基数聚合,例如数百万个分组,从数据库角度来看提出了更大的挑战,但低基数聚合在实践中更为常见,例如按小时对数据集进行分组。为了避免再次受限于内存,哈希计算使查询有意地更加 CPU 密集。

以下是不同查询线程数下的结果:

max_threads时间加速比效率
1884.11.00100.00%
2437.62.02101.02%
4221.34.0099.88%
8110.67.9999.92%
1655.715.8799.20%
3227.432.27100.83%
6413.963.6099.38%
1287.2122.7995.93%
1765.4163.7293.02%
2564.9180.4370.48%
3524.9180.4351.26%

运行时间再次几乎完美地随核心数扩展。Vera 的神经分支预测和复杂的预取帮助 ClickHouse 高效地写入和读取哈希表,并掩盖由数据倾斜引起的访问延迟。与前一个查询一样,效率在超过物理核心数后开始下降,因为计算密集型查询只能有限地利用 SMT。

这是 EXPLAIN PIPELINE 的输出:

1EXPLAIN PIPELINE2SELECT3    ascii(s) AS first_char,4count(),5sum(sipHash64(s))6FROM strings7GROUPBY first_char8SETTINGS max_threads =352;
1┌─explain─────────────────────────┐2│ (Expression)                    │3│ ExpressionTransform × 352       │4│   (Aggregating)                 │5│   Resize × 14 26 → 26           │6│     AggregatingTransform × 352  │7│       (Expression)              │8│       ExpressionTransform × 352 │9│         (ReadFromMemoryStorage) │10└─────────────────────────────────┘

最好从下往上理解该计划。ExpressionTransform 在 352 个并行流中为每个表行计算 ascii(分组键)和 sipHash(sum 的参数)。AggregatingTransform 然后为每个流创建哈希表,当最后一个流处理完成时,将它们合并为一个组合哈希表。这两个算子完全并行化,并充分利用硬件资源。该计划还包含另外两个算子:Resize 再次拆分组合哈希表,并将其条目分散到下一个算子——ExpressionTransform——的各个输入中。在这个查询中,哈希表只有少数条目(256 个),但 ClickHouse 无条件地将 resize 算子插入查询计划,因为哈希表大小在运行时才能知道。ExpressionTransform(位于管道的最后)在 SELECT 列表中计算额外的表达式。在这个查询中,SELECT 列表直接引用了分组表达式和聚合结果——聚合后没有发生额外的计算,该算子基本上不执行任何工作。但假设它必须执行一些工作,ExpressionTransform 也会以最大并行度运行。

微基准测试 3:连接

第三个也是最后一个微基准测试是与较小表的连接。这代表了事实表与维度表之间连接的常见用例。我对原始表进行了采样,创建了一个包含 625k 行(占原始表的 0.001%)的维度表:

1CREATE TABLE strings_tiny2(3    s String4)5ENGINE = Memory;67INSERT INTO strings_tiny8SELECT s FROM strings9WHERE rand() %99999=010LIMIT 625000;

接下来,我运行了一个简单的连接查询:

1SELECTcount()2FROM strings AS big JOIN strings_tiny AS small ON big.s = small.s;

以下是结果:

max_threads时间加速比效率
11132.61.00100.00%
25542.04102.22%
4286.13.9698.97%
8138.78.17102.07%
1671.215.9199.42%
3235.931.5598.59%
6417.863.6399.42%
1289.3121.7895.14%
1767.3155.1588.15%
2566.1185.6772.53%
3526.1185.6752.75%

运行时间几乎与查询线程数成比例下降。换句话说,ClickHouse 完美扩展。

该查询的 EXPLAIN PIPELINE 语句相当复杂,因此我在这里省略它。该连接使用了 ClickHouse 的 parallel_hash 连接算法,描述见 此处,确保哈希表可以由所有查询线程并行构建。它还构建了一个 运行时过滤器 以加速探测哈希表。在实践中,连接列通常是事实表主键的一部分(“外键连接”)。在这个实验中,没有表有主键,但如果有,它将解锁 另一个性能优化,这是我们最近引入的。

附加内容:SIMD 向量化

上述三个微基准测试主要依赖多线程来加速查询处理。另一种并行化数据处理的方式是 SIMD——单指令多数据。ClickHouse 充分利用硬件的 SIMD 能力,使用 编译器自动向量化 或 内联函数 来加速热循环。在这些频繁重复的代码段中,CPU 一次处理多个值,而不是逐个处理每个值。

因此作为附加内容,我在 Vera 机器上运行了以下简单的过滤查询,以说明 SIMD 的好处。为了演示目的,我禁用了多线程:

1CREATE TABLE t (x UInt32) ENGINE = Memory;2INSERT INTO t SELECT rand() FROM numbers(2500000000);34SELECTcount()5FROM t6WHERE x >20000000007FORMAT Null8SETTINGS max_threads =1;

该查询在 0.42 秒内完成。

接下来,我打开了 ClickHouse 的 C++ 代码中的 WHERE 过滤器实现:

1/// From src/Functions/FunctionsComparison.h2staticvoidconst ContainerA & a, B b, PaddedPODArray<UInt8> & c)3{4size_t size = a.size();5const A * __restrict a_pos = a.data();6    UInt8 * __restrict c_pos = c.data();7const A * a_end = a_pos + size;89while (a_pos < a_end)10    {11        *c_pos = Op::apply(*a_pos, b);12        ++a_pos;13        ++c_pos;14    }15}))

a 和 b 代表过滤条件的左侧和右侧——即 x 和 2000000000。Op::apply(“应用操作”)为一组输入行计算 a < b 并将结果作为 c 返回。

为了演示 ClickHouse 如何从强大的 SIMD 指令中受益,我指示编译器通过插入来禁用自动向量化Pragma("clang loop vectorize(disable) interleave(disable)")直接放在 while 循环之前。这让 ClickHouse 顺序比较输入值,而不应用 SIMD 指令。结果,该查询现在的执行时间为 1.48 秒,比之前慢 3.5 倍。开启自动向量化后,ClickHouse 使用 Vera 的 128 位 NEON 指令同时比较四个 32 位整数(理论加速为 4 倍)。除 NEON 之外,Vera 还提供强大的 6x128 位 SVE2 实现,可在其执行单元之间实现显著更高的向量处理吞吐量。ClickHouse 对这些指令的支持目前正与开源社区共同添加中:PR #122860。

总结

“NVIDIA Vera 是一个令人难以置信的快速且强大的服务器平台——是我们迄今见过最快的。ClickHouse 致力于将其巨大潜力转化为世界级的分析性能。” — Alexey Milovidov,ClickHouse 首席技术官

尽管 ClickHouse 如今已能在高核心数机器上良好运行,ClickHouse 工程团队当然会持续质疑现状。查询执行过程中是否存在任何低效之处?查询流水线的各个步骤是否尚未充分利用硬件并行性?数据结构能否做得更紧凑,从而更具缓存效率?数据库能否更好地利用压缩、异步处理、批处理或缓存?敬请期待后续博客文章,了解 ClickHouse 的性能工程,我们将在其中揭示 ClickHouse 如何在规模上分析、优化和测试查询性能。

有关 NVIDIA Vera 的更多信息,请访问:https://developer.nvidia.com/blog/nvidia-vera-cpu-boosts-ai-factory-throughput-to-accelerate-agentic-workloads/

这篇内容对你有用吗?

反馈只用于改善内容筛选,不等同于收藏

分享这条资讯
分享海报
保存图片
iOS 也可以长按图片保存