Star Schema Benchmark · SF=100 & SF=500
Nirvana Labs×Altinity

34 ms against a 3-billion-row table.

On a single ClickHouse node

Managed service for ClickHouse® on Nirvana × Altinity. Single-node ClickHouse 25.8.16, managed by Altinity, running on Nirvana high-performance cloud. Star Schema Benchmark at SF=100 and SF=500, full per-query latency from three executions per query: run 1 approximately cold, runs 2-3 warm.

Single-node · ClickHouse 25.8.16 · SSB SF=100 and SF=500

34ms

Selective query against a 3-billion-row table

SF=500 · Q1.3 warm average

~70M rows/sec

Sustained scan throughput from disk

SF=500 · full-scan family · sustained

3B rows

Largest dataset tested · lineorder_flat

SF=500 · single-node

01 · Purpose

Why we ran it at two sizes.

The Star Schema Benchmark (SSB) is a benchmark for OLAP databases that stresses scans, filters, aggregations, and joins on a star schema. Most published results, ours included, run against lineorder_flat because it removes join overhead and isolates storage + query-execution behavior. Running it at two scale factors separates cached / CPU-bound performance from storage-bound performance. Both matter, but only one looks like a real production workload.

SF=100 · cached

600M rows · fits in page cache · CPU-bound

At SF=100 the working set fits comfortably in the OS page cache after the cold run, so most reads are satisfied from RAM. Warm averages here approach the CPU-bound limit — how fast ClickHouse can parse, decompress, and aggregate data already in memory. Useful as an upper bound; less useful as a production prediction.

SF=500 · disk-bound

3B rows · exceeds page cache · I/O matters

At SF=500 the working set exceeds RAM. Every warm run has to fetch cold blocks from disk, so latency rises and the ceiling becomes storage bandwidth rather than CPU. This is the production-realistic baseline: the number to quote when sizing a real cluster.

02 · Cluster topology

What we tested on.

Everything below was measured on a single-node ClickHouse 25.8.16 cluster managed end-to-end by Altinity, running on Nirvana high-performance cloud.

Cluster under test

Cluster
nirvanalabs-o5nod.altinity.cloud
Engine
ClickHouse 25.8.16
Storage policy
Two-volume default; JBOD biases writes to the emptier volume
Table
lineorder_flat · PARTITION BY toYear(LO_ORDERDATE)
Operator
Altinity.Cloud — fully managed
Substrate
Nirvana Labs purpose-built cloud
Workload
SSB SF=100 + SF=500 · 13 queries · 3 runs each · single session
Volume default/var/lib/clickhouse · ~344 GiBJBOD bias
Volume disk2/var/lib/clickhouse2 · ~344 GiBJBOD bias
03 · Dataset

How much data we loaded.

SSB is a denormalized star schema derived from TPC-H. We load all five base tables, then build lineorder_flat — the canonical wide table the SSB queries hit — at both scale factors.

lineorder
Role
Fact
SF = 100
600,037,902
SF = 500
2,999,989,709
lineorder_flat
Role
Wide fact (canonical SSB table)
SF = 100
600,037,902
SF = 500
2,999,989,709
customer
Role
Dimension
SF = 100
3,000,000
SF = 500
15,000,000
supplier
Role
Dimension
SF = 100
200,000
SF = 500
1,000,000
part
Role
Dimension
SF = 100
1,400,000
SF = 500
1,800,000
date
Role
Dimension
SF = 100
2,556
SF = 500
2,556

lineorder_flat is the denormalized join of lineorder with all four dimensions. The 13 SSB queries operate exclusively on this table, which is why all query timings below are scaled by its row count.

04 · Methodology

How we ran it.

Three blocks below — build, load, query — reproduced from the run log as executed. Where we would do something differently next time, it is called out as a recommendation in the remarks below rather than folded in here.

We use the canonical vadimtk/ssb-dbgen generator. Build it on the same host that will load data — keeps the I/O local and avoids large network copies of the raw .tbl files.

Generate each table at the chosen scale factor and stream it into ClickHouse. Dim tables load immediately and free their .tbl; the fact table is split into parallel chunks at SF=100 and single-streamed at SF=500.

SSB queries hit the wide denormalized lineorder_flat. Build it once per scale factor, then run each of the 13 queries three times back-to-back: run 1 is approximately cold, runs 2-3 are warm.

05 · Results

Selective queries stay under 100 ms. Full scans take 24–44 seconds.

Toggle between SF=100 and SF=500. Filter by query class to isolate selective lookups, partition-bounded aggregates, and full scans. Hover any bar for the full per-run breakdown. SF=100 latencies are in ms; SF=500 in seconds.

Scale factor
Query class
Warm-average latency · log scale (s)
Index hitHighly selectivePartition-boundedFull scan
Q1.1Year filter; sum revenue × discount.
Class
Partition-bounded
Warm avg
1.38 s
Run 1 (~cold)
4.48 s
Warm runs
1.34 / 1.41 s
Rows scanned
91M
Q1.2Year + month + discount band; tight aggregate.
Class
Partition-bounded
Warm avg
0.11 s
Run 1 (~cold)
0.41 s
Warm runs
0.11 / 0.11 s
Rows scanned
7.8M
Q1.3Year + week + quantity band; narrow slice of fact table.
Class
Highly selective
Warm avg
0.034 s
Run 1 (~cold)
0.16 s
Warm runs
0.03 / 0.04 s
Rows scanned
1.8M
Q2.1Revenue by year × brand for one part category.
Class
Full scan
Warm avg
31.05 s
Run 1 (~cold)
31.84 s
Warm runs
32.37 / 29.72 s
Rows scanned
600M
Q2.2Revenue by year × brand for one brand range.
Class
Full scan
Warm avg
28.13 s
Run 1 (~cold)
29.35 s
Warm runs
26.53 / 29.73 s
Rows scanned
600M
Q2.3Revenue by year × brand for one brand.
Class
Full scan
Warm avg
27.12 s
Run 1 (~cold)
26.4 s
Warm runs
28.64 / 25.6 s
Rows scanned
600M
Q3.1Revenue by region × year; reads ~91% of the fact table.
Class
Full scan
Warm avg
31.02 s
Run 1 (~cold)
31.41 s
Warm runs
29.96 / 32.09 s
Rows scanned
547M
Q3.2Revenue by nation × year (one region); ~91% of rows read.
Class
Full scan
Warm avg
24.71 s
Run 1 (~cold)
24.07 s
Warm runs
24.85 / 24.58 s
Rows scanned
547M
Q3.3Revenue by city × year (one nation); ~91% of rows read.
Class
Full scan
Warm avg
24.33 s
Run 1 (~cold)
22.08 s
Warm runs
25.57 / 23.09 s
Rows scanned
547M
Q3.4Year + month + city + city; primary-index hit.
Class
Index hit
Warm avg
0.063 s
Run 1 (~cold)
0.055 s
Warm runs
0.064 / 0.062 s
Rows scanned
7.7M
Q4.1Profit by year × nation for one region (largest scan).
Class
Full scan
Warm avg
43.76 s
Run 1 (~cold)
44.79 s
Warm runs
45.08 / 42.45 s
Rows scanned
600M
Q4.2Profit by year × nation, 2-year window.
Class
Partition-bounded
Warm avg
5.29 s
Run 1 (~cold)
8.72 s
Warm runs
6.73 / 3.85 s
Rows scanned
144M
Q4.3Profit by year × city, 2-year, one nation.
Class
Partition-bounded
Warm avg
3.45 s
Run 1 (~cold)
4.24 s
Warm runs
3.91 / 2.98 s
Rows scanned
144M

SF=500 (disk-bound, 3B rows), values in s · 3 executions per query (run 1 ≈cold, runs 2-3 warm) · 13 of 13 queries.

06 · Scaling characteristics

Selective queries stayed interactive as the dataset grew 5×.

Five times the data, and selective queries still answer in under 100 ms (34 ms and 63 ms warm): latency grew 2.8–3.9×, well behind the data. Full scans move from cache speed to disk speed over the same jump, which is where the 13–35× figure comes from: at 600M rows the table fits in page cache, at 3B rows it doesn’t. That’s a change of substrate, not a loss of efficiency, and it settles into a predictable ~70M rows/sec.

Per-query latency · SF=100 → SF=500 · log scale (ms)
Index hitHighly selectivePartition-boundedFull scan
~70Mrows/s

Sustained SF=500 scan throughput from disk

2.8–3.9×

Selective-query latency growth · 5× more data

34ms

Q1.3 warm latency against a 3B-row table · SF=500

13–35×

Full-scan latency growth at SF=500

Each line is one of the 13 queries. The selective query and the index hit (Q1.3, Q3.4) stay near the bottom across both scale factors. The full scans trend upward at SF=500 as the dataset moves past page-cache size and warm runs pull cold blocks from disk.

07 · Observations

Five things we learned.

01

Selective queries are the strong signal.

Q3.4 lands at 63 ms warm against a 3-billion-row table because a tight (year, month, city, city) filter rides partition pruning (toYYYYMM = 199712) and sort-key skipping (LO_ORDERDATE first in the order key). It reads 7.7M rows, not 3B. Q1.3 sits at 34 ms on 1.8M rows read, for the same reason. This is what well-aligned analytical queries look like at this hardware class.

02

Memory never became a constraint.

At SF=100, peak memory across all 13 queries was ~16 MB: ClickHouse aggregates in place over streamed data, and nothing tripped the external group-by or external sort thresholds. SF=500 memory was not captured. The work is read-bound rather than memory-bound, so similar behavior is expected — but that is an expectation, not a measurement.

03

Full-scan throughput is solid and predictable.

At SF=500, Q4.1 reads 3B rows in 43.76 s warm: roughly 70M rows/sec sustained from disk. The same query at SF=100 read 600M rows in 2.80 s, about 215M rows/sec from cache. That ~3× gap between cached and disk-bound is the number to plan capacity against.

04

Performance is stable run to run.

Repeat runs land on the same number: Q3.2 at 24.85 s then 24.58 s, Q4.1 at 45.08 s then 42.45 s. The cold-to-warm ratio narrows from 2–5× at SF=100 to 1.0–1.1× at SF=500: past cache, first and second runs both read from disk, so there is no cache bonus to chase. Q4.2 (8.72 → 6.73 → 3.85 s) is the one outlier — I/O variance, not query variance.

05

Size for the working set, not the cache.

Full scans at SF=500 run at disk speed rather than cache speed, which is why their latency grows 13–35× while the dataset grows 5×. Q3.1–Q3.3 are counted in this family: they read roughly 91% of the fact table, so they behave like scans rather than bounded aggregates. SF=500 is the production-realistic baseline; SF=100 measures CPU and decompression in isolation.

08 · Comparison context

Fast selective queries. Predictable storage-bound scans.

Selective queries — the shape most production dashboards actually run — land at 34–63 ms against a 3-billion-row table. That’s the headline number, and it’s the one to quote. We are not publishing a comparison against other clouds here: a parity claim needs the same dataset and the same queries measured on both sides, and we have only run one side.

This run · what it establishes34–63 ms

warm selective queries against a 3-billion-row table, and ~70M rows/sec sustained on storage-bound full scans

Single-node ClickHouse 25.8.16, Altinity-managed, Nirvana compute · SSB SF=500.

On comparisons. Published single-node ClickHouse numbers vary widely with CPU, RAM, storage class and settings, and we did not run any of them ourselves, so quoting a range from memory would not be evidence of anything. If you want a comparison, the useful one is your own workload on both substrates: bring your dataset and queries and we’ll measure them side by side.

09 · Remarks

Remarks for anyone reproducing this.

What went wrong, what we would do differently, and the details that decide whether your run matches ours.

10 · Why Nirvana

Why these numbers look like this.

The performance above isn’t accidental. Nirvana is purpose-built for analytical workloads like ClickHouse. The substrate matters, especially at SF=500 where storage bandwidth becomes the ceiling.

Co-located stack

Compute and storage, one private-network hop apart.

Your ClickHouse, workload (like a decision engine), and even blockchain node sit on the same private network on Nirvana’s infrastructure. The compute and ClickHouse process sit on the same Kubernetes node, with storage one private-network hop away — no public-internet round trip between the engine and its working set.

Block storage

Purpose-built block storage, no hyperscaler underneath.

Nirvana built the entire cloud stack in-house. Nirvana ABS gives you 20,000 baseline IOPS included with no per-IOP surcharges, multi-GB/s bandwidth at large block sizes, and stable sequential read throughput under sustained load.

Dedicated

Dedicated ClickHouse per customer.

Multi-tenant ClickHouse was explicitly rejected for security and compliance reasons. Each customer gets a dedicated cluster running on shared underlying infrastructure with Kubernetes-level isolation.

Managed

Altinity-operated.

ClickHouse 25.8.16 fully managed by Altinity, running on Nirvana NKS: one operational support path for both the engine and the substrate.

Next step

Benchmark your ClickHouse workload on Nirvana.

Bring your own dataset or your own queries and compare performance on the same infrastructure this report was measured on.

Request a benchmark
Single-node benchmark · ClickHouse 25.8.16ClickHouse® is a registered trademark of ClickHouse, Inc.; Altinity is not affiliated with or associated with ClickHouse, Inc.

Powering AI, blockchain, and
databases

Talk to Sales