Skip to content

Performance ​

Arneb is measured against Trino on the 22 TPC-H queries, with both engines run the same way: a coordinator plus two workers in containers with the same per-node CPU cap, reading the same Snappy Parquet from the same object store through the same Hive Metastore. Correctness is a separate gate: every query is compared cell by cell against Trino, and all 22 match at both scale factors below.

ScaleProtocolReleaseLatency (Trino ÷ Arneb, geomean)Peak memory (Arneb ÷ Trino, mean)Faster on
SF10warmv0.1.22.3×0.14×22 / 22
SF10coldv0.1.24.6×0.14×22 / 22
SF30coldv0.1.33.5×0.22×22 / 22

Arneb vs Trino, TPC-H SF30 cold: latency and peak memory per query

Quote the warm SF10 column. A cold run recreates the cluster, so Trino's figure includes the JVM re-JITting its code, a start-up cost Arneb does not have: warming is worth a median 56% to Trino and 9% to Arneb at SF10.

SF10 ​

Measured 2026-10-14 on one host (10 CPUs, 15.66 GiB of container-runtime memory) from the code released as v0.1.2. lineitem is 59,986,052 rows. Latency is in milliseconds and peak memory in MB; memory is the largest simultaneous resident set summed across all three nodes, from the warm run.

Querycold arnebcold Trinocoldwarm arnebwarm Trinowarmmem arnebmem Trinomem
q01Pricing Summary2,0686,3093.1×1,8522,6781.4×3576,0890.06×
q02Minimum Cost Supplier6385,7499.0×4922,0174.1×3463,8120.09×
q03Shipping Priority2,3388,2763.5×2,1474,0011.9×1,9056,1260.31×
q04Order Priority Checking1,4257,0144.9×1,2643,1572.5×6696,6070.10×
q05Local Supplier Volume2,3637,9833.4×1,9973,8291.9×1,1155,7610.19×
q06Forecasting Revenue7654,5956.0×6981,8902.7×3214,5250.07×
q07Volume Shipping2,0418,0523.9×1,8894,5742.4×1,2027,5900.16×
q08National Market Share2,9309,2853.2×2,7595,2121.9×1,5857,1010.22×
q09Product Type Profit4,90911,1842.3×4,6256,1931.3×1,7328,4890.20×
q10Returned Item Reporting2,18010,3074.7×2,1884,4772.0×9395,9760.16×
q11Important Stock ID7625,3557.0×6942,1923.2×2653,3490.08×
q12Shipping Modes1,2026,3115.3×1,0782,5752.4×4365,5040.08×
q13Customer Distribution1,6577,4184.5×1,4544,0202.8×4475,6680.08×
q14Promotion Effect1,4636,9094.7×1,2013,0082.5×9245,0340.18×
q15Top Supplier1,1456,8466.0×1,0333,3513.2×4036,6800.06×
q16Parts/Supplier Relationship1,0567,2206.8×9882,2832.3×5344,0880.13×
q17Small-Quantity-Order Revenue3,04210,7463.5×2,9695,5591.9×1,3778,7460.16×
q18Large Volume Customer4,17410,8182.6×4,0946,0701.5×2,22110,8890.20×
q19Discounted Revenue1,5877,5774.8×1,3393,2092.4×6715,3020.13×
q20Potential Part Promotion1,3848,6516.2×1,2543,7383.0×8065,5320.15×
q21Suppliers Who Kept Orders Waiting3,25515,2754.7×3,4136,9762.0×1,0677,6240.14×
q22Global Sales Opportunity8785,5586.3×8032,1862.7×3204,6380.07×
aggregate4.6×2.3×0.14×

Latency aggregates are geometric means; the memory aggregate is an arithmetic mean.

Memory, in absolute terms ​

The five largest gaps at SF10:

QueryArnebTrinoSaved
q18 Large Volume Customer2.2 GB10.6 GB8.5 GB
q17 Small-Quantity-Order Revenue1.3 GB8.5 GB7.2 GB
q09 Product Type Profit1.7 GB8.3 GB6.6 GB
q21 Suppliers Who Kept Orders Waiting1.0 GB7.4 GB6.4 GB
q07 Volume Shipping1.2 GB7.4 GB6.2 GB

At idle, before any query, Trino's three-node cluster holds 1.99 GB of committed heap (1.84–2.15 GB across 44 restarts); Arneb's holds 0.07 GB.

SF30, cold ​

Measured 2026-10-18 on a separate benchmark host, cold protocol only, one run per query, from the code released as v0.1.3. Latency is in seconds; memory is the simultaneous cluster peak in GB (KiB ÷ 10⁶), with Trino's derived from the recorded ratio, so it is good to about 2%. The oracle was 22/22 clean, deterministic over two runs. Numbers from this host are not comparable with the SF10 table.

QueryArneb (s)Trino (s)LatencyArneb (GB)Memory
q01Pricing Summary19.546.52.4×0.350.06×
q02Minimum Cost Supplier6.145.07.4×0.660.16×
q03Shipping Priority29.565.32.2×1.650.23×
q04Order Priority Checking14.155.33.9×0.610.07×
q05Local Supplier Volume24.575.93.1×2.190.35×
q06Forecasting Revenue7.031.64.5×0.340.06×
q07Volume Shipping28.769.42.4×1.360.26×
q08National Market Share21.877.33.5×1.140.17×
q09Product Type Profit49.1130.92.7×1.940.17×
q10Returned Item Reporting20.394.24.6×2.080.39×
q11Important Stock ID8.437.54.5×1.090.26×
q12Shipping Modes13.545.23.3×0.860.17×
q13Customer Distribution16.570.24.3×0.990.14×
q14Promotion Effect12.143.93.6×1.480.25×
q15Top Supplier13.265.34.9×0.500.07×
q16Parts/Supplier Relationship10.753.45.0×1.060.19×
q17Small-Quantity-Order Revenue31.283.22.7×4.290.52×
q18Large Volume Customer49.186.01.8×5.330.48×
q19Discounted Revenue12.949.33.8×0.750.12×
q20Potential Part Promotion15.863.54.0×1.070.15×
q21Suppliers Who Kept Orders Waiting65.4169.72.6×4.340.48×
q22Global Sales Opportunity7.837.44.8×0.500.09×
aggregate3.5×0.22×

The v0.1.2 run on 2026-10-15 got 3.7× and 0.21×. This release adds no performance work, and the difference is inside run-to-run noise. The second half of that earlier run was also slowed for both engines by the host: Trino's own q21 took 207 s, against 170 s here.

The chart is drawn from the run's data by benchmarks/tpch/scripts/plot_comparison.py, which reads any run_memory_bench CSV:

bash
python3 benchmarks/tpch/scripts/plot_comparison.py \
    benchmarks/tpch/results/memory_total_<stamp>.csv --mode cold \
    -o chart.svg --title "Arneb vs Trino — TPC-H SF30, cold"

What changed in v0.1.3 ​

v0.1.3 is about running Arneb safely next to other workloads, not about speed:

  • Security: TLS on pgwire and on the Trino listener (HTTPS), password authentication on both against the same users, and a shared secret plus TLS on the coordinator–worker Flight RPC. See Authentication, TLS and Securing the Cluster.
  • Admission control: a cap on running queries with a queue behind it, a per-query memory limit on every node, statement_timeout, and cancellation that reaches the workers. See Admission Control.
  • Memory accounting: Parquet scans now count their decode buffers in the memory pool, so the per-query limit and a join's spill decision see the real usage. In the run above, no join spilled earlier because of it; arneb's median peak was 0.97× that of the run before the change.
  • Exchange resilience: a worker-to-worker broadcast read that breaks on the transport (for example an h2 BrokenPipe under many concurrent queries) is reopened and resumed from the first row not yet delivered, instead of failing the query.

What changed in v0.1.2 ​

The largest wins in this release came from the semi and anti joins (EXISTS, NOT EXISTS, IN subqueries):

  • Hash-partitioned semi/anti joins. Both sides are partitioned on the join key across the workers, instead of one worker receiving the whole build and probe side. At SF10 warm this took q21 −21%, q04 −22% and q22 −20%.
  • Probe-side key-set filters. When the build side of a partitioned semi/anti join is large (estimated ≥ 20M rows and ≥ 4× the probe side), each join task reads the small side first and publishes its keys, as a Bloom filter above 20K keys, to the scans on the big side, which drop non-matching rows before the shuffle. q21 went from losing to Trino (0.8×) to 2.0× at SF10 warm, and q22's SF30 peak memory fell from about 1.75 GB to 0.52 GB. The filter is not attached when the small side itself scans more than 100M rows, since the big side would mostly be read before the keys arrived; that is the case for q21 at SF30.
  • q18 builds the smaller join side and runs its IN-subquery final aggregate in parallel across workers.
  • Decorrelated aggregates under a semi join are pre-filtered by the outer key set.

Every one of these is on by default, with an ARNEB_* variable to switch it off for A/B comparisons; see Query Engine Levers.

Limits ​

  • One host and one run per protocol per query for each table. Repeated SF10 runs put run-to-run noise at a median of 4–6% per query (worst 29%), so single-query differences under about 30% are not results.
  • q18's peak memory at SF10 varied between 2.0 and 4.7 GB across the runs above (one worker peaked at about twice the other); it has not recurred since the dataset was re-seeded, and the seed now writes a fixed layout (#126).
  • SF30 has not been measured warm.

Reproduce it ​

bash
git clone https://github.com/formosa-ventures/arneb.git && cd arneb

docker compose -f docker-compose.yml \
               -f docker/arneb-bench/docker-compose.bench.yml build

./benchmarks/tpch/scripts/run_benchmark.sh --scenario=sf10 --mode=both
python3 benchmarks/tpch/scripts/blast_radius_oracle.py --runs 2

The method (engine rotation, how memory is sampled, host floors) is described in the README, and the full harness guide is in benchmarks/tpch/README.md.