sgcPivotGrid 基准测试
sgcPivotGrid 引擎 TsgcPivotEngine 在 1,000,000 行和 10,000,000 行数据上的实测时间:加载数据、以单次遍历和并行计算重新计算三种透视布局,以及引擎在数据之外增加的内存。每个数字都来自 sgcUI 演示中的基准测试程序,因此您可以在自己的硬件上运行同样的测试。
sgcPivotGrid 引擎 TsgcPivotEngine 在 1,000,000 行和 10,000,000 行数据上的实测时间:加载数据、以单次遍历和并行计算重新计算三种透视布局,以及引擎在数据之外增加的内存。每个数字都来自 sgcUI 演示中的基准测试程序,因此您可以在自己的硬件上运行同样的测试。
数据行由固定的随机种子生成,因此每台机器计算的透视结果都相同。每种模式都会检查 P1 的总计是否等于数值列之和。
| 场景 | 程序的操作 |
|---|---|
| 加载 | 用 AppendRow 加载 1,000,000 或 10,000,000 行,每行包含 3 个文本值、1 个数字和 1 个日期。文本在到达时被编码为成员索引。第二步通过 Store.SetFloat 为一个数字列填入 100,000 个不同的值。 |
| P1 Sum | 2 个行字段(50 个地区乘以 20 个产品,加上小计和总计共 1,051 个行项)和 1 个列字段(12 个月),对一个值求 Sum。最基本的透视。 |
| P3 CountDistinct | P1 布局,统计具有 100,000 个不同值的列的不同值个数,这是最耗时的标准聚合。 |
| P4 StdDev, Average, Max | 在 P1 布局上同时计算三个度量。 |
| 单次遍历 | 默认引擎,ParallelCalculation 关闭。 |
| 1 至 14 线程 | 设置 MaxThreads 并令 ParallelCalculation := True 和 ParallelThreshold := 1,因此 1,000,000 行也会并行运行。“所有 CPU”即 MaxThreads := 0,每个逻辑 CPU 一个线程,测试机器上为 14 个。 |
| 引擎内存 | 引擎在已加载数据之外为 P1 分配的内存(QA 关卡 M1)。存储内存是已加载数据本身。 |
一台带有正常桌面负载的开发工作站,而不是隔离的实验室机器。测量日期为 2026 年 11 月 4 日。
| 项目 | 值 |
|---|---|
| CPU | Intel Core Ultra 5 245T,35 W 桌面处理器 |
| 核心 | 6 个性能核心和 8 个能效核心,14 个逻辑 CPU |
| 内存 | 31.5 GB |
| 操作系统 | Windows 11 Pro 26H2 (build 26300) |
| 编译器 | Delphi 13 Florence,发布版本:开启优化,关闭范围检查和溢出检查 |
| 平台 | Win64(1 次预热运行后取 5 次运行的中位数)和 Win32(快速运行:1 次预热运行后 1 次计时运行) |
| sgcPivotGrid | 2026.11.0 Registered |
该处理器混合了高性能核心和能效核心,每个工作线程运行在哪个核心由 Windows 决定。使用 8 个或更多线程时,部分工作会落在能效核心上:Win64 下 1,000,000 行的 P4 会在约 13 ms 和约 32 ms 之间交替,因此 8 线程时其中位数跳到 31.2 ms。
1 次预热运行后取 5 次运行的中位数。时间单位为毫秒。
| 加载与内存 | 1,000,000 行 | 10,000,000 行 |
|---|---|---|
AppendRow,3 个文本列、1 个浮点列、1 个日期列 | 132.9 ms | 1,384.0 ms |
Store.SetFloat,1 个具有 100,000 个不同值的浮点列 | 8.6 ms | 98.3 ms |
| 存储内存(6 列) | 36.0 MB | 576.0 MB |
| P1 之后的引擎内存,所有模式 | 4.8 MB | 39.1 MB |
| 模式 | 线程 | P1 Sum | P3 CountDistinct | P4 StdDev, Average, Max |
|---|---|---|---|---|
| 单次遍历 | 1 | 13.9 ms | 25.6 ms | 26.3 ms |
| 并行,1 线程 | 1 | 12.2 ms | 21.6 ms | 26.3 ms |
| 并行,2 线程 | 2 | 9.6 ms | 18.2 ms | 17.8 ms |
| 并行,4 线程 | 4 | 7.1 ms | 15.9 ms | 12.9 ms |
| 并行,8 线程 | 8 | 6.8 ms | 15.3 ms | 31.2 ms |
| 并行,所有 CPU | 14 | 6.8 ms | 16.5 ms | 31.8 ms |
| 模式 | 线程 | P1 Sum | P3 CountDistinct | P4 StdDev, Average, Max |
|---|---|---|---|---|
| 单次遍历 | 1 | 121.1 ms | 300.2 ms | 216.9 ms |
| 并行,1 线程 | 1 | 106.4 ms | 253.0 ms | 230.6 ms |
| 并行,2 线程 | 2 | 67.1 ms | 212.7 ms | 130.3 ms |
| 并行,4 线程 | 4 | 46.9 ms | 184.6 ms | 127.5 ms |
| 并行,8 线程 | 8 | 63.6 ms | 181.1 ms | 111.9 ms |
| 并行,所有 CPU | 14 | 73.5 ms | 186.4 ms | 105.4 ms |
快速运行:1 次预热运行后 1 次计时运行,因此这些数字比 Win64 的中位数噪声更大。该程序支持大地址空间(large address aware),这是 10,000,000 行存储所必需的。
| 加载与内存 | 1,000,000 行 | 10,000,000 行 |
|---|---|---|
AppendRow,3 个文本列、1 个浮点列、1 个日期列 | 143.7 ms | 1,511.9 ms |
Store.SetFloat,1 个具有 100,000 个不同值的浮点列 | 16.8 ms | 183.7 ms |
| 存储内存(6 列) | 36.0 MB | 576.0 MB |
| P1 之后的引擎内存,所有模式 | 4.7 MB | 39.1 MB |
| 模式 | 线程 | P1 Sum | P3 CountDistinct | P4 StdDev, Average, Max |
|---|---|---|---|---|
| 单次遍历 | 1 | 16.9 ms | 27.3 ms | 50.8 ms |
| 并行,1 线程 | 1 | 16.7 ms | 22.9 ms | 51.0 ms |
| 并行,2 线程 | 2 | 11.3 ms | 20.4 ms | 32.8 ms |
| 并行,4 线程 | 4 | 8.6 ms | 16.3 ms | 23.1 ms |
| 并行,8 线程 | 8 | 8.5 ms | 16.3 ms | 19.2 ms |
| 并行,所有 CPU | 14 | 8.5 ms | 15.6 ms | 19.2 ms |
| 模式 | 线程 | P1 Sum | P3 CountDistinct | P4 StdDev, Average, Max |
|---|---|---|---|---|
| 单次遍历 | 1 | 143.6 ms | 286.8 ms | 442.6 ms |
| 并行,1 线程 | 1 | 139.4 ms | 253.6 ms | 463.7 ms |
| 并行,2 线程 | 2 | 88.0 ms | 207.8 ms | 252.4 ms |
| 并行,4 线程 | 4 | 52.5 ms | 176.8 ms | 141.7 ms |
| 并行,8 线程 | 8 | 57.2 ms | 167.1 ms | 159.6 ms |
| 并行,所有 CPU | 14 | 64.4 ms | 172.0 ms | 131.9 ms |
基准测试程序的 .NET 移植版,使用与 Delphi 程序相同的数据行、布局和模式。它运行在另一个运行时上,因此请将这些数字视为独立的表格。1 次预热运行后取 5 次运行的中位数。时间单位为毫秒。
| 加载与内存 | 1,000,000 行 | 10,000,000 行 |
|---|---|---|
AppendRow,3 个文本列、1 个浮点列、1 个日期列 | 75.6 ms | 770.4 ms |
Store.SetFloat,1 个具有 100,000 个不同值的浮点列 | 2.9 ms | 43.0 ms |
| 存储内存(6 列) | 36.0 MB | 576.0 MB |
| P1 之后的引擎内存,所有模式 | 4.7 MB | 39.1 MB |
运行时:.NET 8.0.31,x64 进程,发布版本,使用 sgcPivotGrid 2026.11.0 Registered 的 net8.0 控制台程序,在上述测试机器上于同一天测得。内存是存活的托管堆,在完整回收之后用 GC.GetTotalMemory(true) 测得。
| 模式 | 线程 | P1 Sum | P3 CountDistinct | P4 StdDev, Average, Max |
|---|---|---|---|---|
| 单次遍历 | 1 | 11.9 ms | 23.3 ms | 14.7 ms |
| 并行,1 线程 | 1 | 12.1 ms | 21.3 ms | 20.1 ms |
| 并行,2 线程 | 2 | 8.5 ms | 15.5 ms | 12.6 ms |
| 并行,4 线程 | 4 | 6.3 ms | 14.8 ms | 9.9 ms |
| 并行,8 线程 | 8 | 6.8 ms | 13.6 ms | 9.8 ms |
| 并行,所有 CPU | 14 | 6.6 ms | 13.3 ms | 9.6 ms |
| 模式 | 线程 | P1 Sum | P3 CountDistinct | P4 StdDev, Average, Max |
|---|---|---|---|---|
| 单次遍历 | 1 | 67.6 ms | 275.1 ms | 128.0 ms |
| 并行,1 线程 | 1 | 76.4 ms | 215.0 ms | 175.9 ms |
| 并行,2 线程 | 2 | 44.2 ms | 159.6 ms | 89.9 ms |
| 并行,4 线程 | 4 | 28.8 ms | 133.7 ms | 56.2 ms |
| 并行,8 线程 | 8 | 34.0 ms | 151.7 ms | 72.6 ms |
| 并行,所有 CPU | 14 | 28.3 ms | 154.9 ms | 66.0 ms |
.NET 的 QA 性能测试使用 Delphi 预算的 1.2 倍(x64 下 P1 为 120 ms)。本次运行中 1,000,000 行的每个关卡都在预算之内,并且在每种模式下 P1 的总计都等于各值之和。
PivotGrid\Benchmark\Benchmark.csproj。该文件夹中的 README.md 有详细说明。dotnet-<arch>.md、.json 和 .csv,例如 dotnet-x64.md。dotnet run -c Release
dotnet run -c Release -- --rows=1m,10m --quick
dotnet run -c Release -- --rows=500k,2m --threads=4 --out=C:\benchQA 性能组在每次生成时都会在 Win64 和 Win32 上断言这些预算,任何一项未达标,QA 运行即告失败。10,000,000 行没有预算,QA 只报告其结果。
| 关卡 | 测量内容 | Win64 预算 | Win64 实测 | Win32 预算 | Win32 实测 |
|---|---|---|---|---|---|
| P1 | 重新计算 1,000,000 行,2 个行字段,1 个列字段,1 个 Sum | 100 ms | 13.9 ms | 160 ms | 16.9 ms |
| P1P | 启用 ParallelCalculation 的 P1,每个 CPU 一个线程 | 100 ms | 6.8 ms | 160 ms | 8.5 ms |
| P2 | 用 AppendRow 加载 1,000,000 行,每行 3 个文本值、1 个浮点值和 1 个日期值,包含编码 | 900 ms | 132.9 ms | 1,400 ms | 143.7 ms |
| P3 | P1 布局,对具有 100,000 个不同值的列做 CountDistinct | 400 ms | 25.6 ms | 600 ms | 27.3 ms |
| P4 | P1 布局,计算 StdDev、Average 和 Max | 180 ms | 26.3 ms | 280 ms | 50.8 ms |
| M1 | P1 在存储之上的引擎内存 | 32 MB | 4.8 MB | 32 MB | 4.7 MB |
| M1P | 启用 ParallelCalculation 的 M1,每个 CPU 一个线程 | 32 MB | 4.8 MB | 32 MB | 4.7 MB |
这些预算被有意设得较为宽松,以便在较慢的生成机器上捕获性能回退。在测试机器上,实测值比预算低 5.5 到 22 倍。
表中并行行增加了什么,以及应使用多少线程。Registered
ParallelCalculation := True 会把大规模重新计算拆分为 131,072 行的固定块,在工作线程上计算这些块,并按块顺序合并。MaxThreads 限制工作线程数(0 表示每个 CPU 一个,最多 64 个),ParallelThreshold 默认为 1,000,000 行,使更小的存储继续使用单次遍历。它默认关闭,因为 Sum、Average、Product 以及 StdDev 系列的结果可能在最后几位上与单次遍历不同。它包含在 Registered 和 Trial 版本中。
MaxThreads 设为 4 到 8。在测试机器上,4 线程在 Win64 的两种规模下都给出最佳的 P1:1,000,000 行为 7.1 ms,10,000,000 行为 46.9 ms,而单次遍历分别为 13.9 ms 和 121.1 ms。在您自己的硬件上使用相同的程序、相同的数据行和相同的布局。
Demos\PivotGrid\Delphi\Benchmark\sgcPivotGridBenchmark.dpr。该文件夹中的 README.txt 有详细说明。sgcPivotGridBenchmark [--rows=1m,10m] [--threads=1,2,4,8,0] [--out=folder] [--quick]
sgcPivotGridBenchmark
sgcPivotGridBenchmark --rows=1m,10m --quick
sgcPivotGridBenchmark --rows=500k,2m --threads=4 --out=C:\bench| 开关 | 含义 |
|---|---|
--rows | 要测试的行数,可使用 k 和 m 后缀。 |
--threads | 并行模式的 MaxThreads 值。0 或 all 表示每个 CPU 一个线程。单次遍历始终运行。 |
--out | 输出文件夹,默认为可执行文件旁边的 benchmark 文件夹。 |
--quick | 预热之后只做 1 次计时运行,而不是取 5 次的中位数。 |
每次运行都会写出 delphi-<platform>.md、.json 和 .csv,其中包含机器、设置和每一项计时,并检查 1,000,000 行的 QA 预算。BenchmarkMain.pas 包含全部逻辑,因此您可以用自己的数据替换生成的数据行,并保留相同的计时和报告。如果您的数字与这些相差很大,请告诉我们。
QA 预算也记录在架构帮助主题中。