ClickHouse Cloud performance is now a board-level concern for any enterprise that runs revenue-facing analytics, fraud models or customer dashboards on the service. The managed service removes a great deal of operational toil: no Keeper ensembles to size, no disks to provision, no binaries to patch. It does not remove the engineering decisions that set latency, resilience and the monthly invoice. Those remain the customer’s, and they compound for years.
This paper sets out ChistaDATA’s long-term commitment to ClickHouse Cloud performance and to the customers who depend on it. We cover four pillars, performance, scalability, high availability and FinOps. For each one we state what we own, how we measure it and the code we use. Where we have measured something ourselves, we publish the method alongside the number.
The position in brief
ChistaDATA was built on 100% open-source ClickHouse with zero vendor lock-in, and that does not change. Many enterprises have chosen ClickHouse Cloud, and many more will. Our commitment is to engineer ClickHouse Cloud performance, scale, availability and cost to the same standard we apply to self-managed estates. The same 24x7x365 operations team runs it from the SF Bay Area plus eleven global offices.
In our own lab, codec choices alone cut compressed storage by 60.5 percent, and an hourly rollup cut rows scanned 28.8 times for fleet-wide queries. In the illustrative cost model below, compute is more than twenty times the storage line, so the largest FinOps lever is compute design rather than storage.
Our position on ClickHouse Cloud
We are vendor-neutral by principle, and that applies to ClickHouse Cloud performance advice as much as to platform choice. ClickHouse Cloud fits well when a team wants elastic compute, storage separated from compute, idling for intermittent workloads, and a vendor-operated control plane. Self-managed open-source ClickHouse fits better when the workload is steady and large, when data residency rules require infrastructure the customer controls, or when engine-level control matters. We advise both ways and help customers move in either direction.
What we will not do is treat a managed service as a finished architecture. ClickHouse Cloud performance still depends on sort keys, codecs, rollups and query shape. Resilience still depends on replica placement, backup policy and drills. The invoice still depends on how many compute units are awake and why. Those are engineering responsibilities, and they are the ones we accept.
The operating model: four pillars and one measurement loop
Every engagement runs on the same model. Each pillar has an owner, a metric and a review date, and a change made for one pillar is checked against the other three. A larger replica improves ClickHouse Cloud performance and also raises cost. A shorter idle timeout saves money and also adds cold-start latency. Neither decision is made in isolation.
Figure 1. Four pillars of ClickHouse Cloud performance and cost engineering, each tied to a system table or billing metric and reviewed monthly.
Pillar one: ClickHouse Cloud performance engineering
ClickHouse Cloud performance starts from the same evidence as any ClickHouse estate: system.query_log. A service can have several replicas, so we always read it across all of them. The query below ranks query fingerprints by total bytes read over seven days. Bytes read are the closest single proxy for the compute a query consumes.
SELECT
normalized_query_hash,
any(query) AS sample_query,
count() AS executions,
formatReadableSize(sum(read_bytes)) AS total_read,
round(quantile(0.95)(query_duration_ms)) AS p95_ms,
round(quantile(0.99)(query_duration_ms)) AS p99_ms,
any(user) AS sample_user
FROM clusterAllReplicas('default', system.query_log)
WHERE event_date >= today() - 7
AND type = 'QueryFinish'
AND query_kind = 'Select'
GROUP BY normalized_query_hash
ORDER BY sum(read_bytes) DESC
LIMIT 25;The top twenty-five fingerprints usually account for most of the bytes read. We work down that list with EXPLAIN indexes = 1, checking whether the sort key prunes granules. Where it does not, we change the key, add a projection, or add a rollup.
ClickHouse Cloud performance SLOs per service
Averages hide the queries customers complain about, so ClickHouse Cloud performance is reported as percentiles per user and per hour. This query feeds the monthly review and the alerting thresholds we agree with each customer:
SELECT
toStartOfHour(event_time) AS hour_bucket,
user,
count() AS queries,
round(quantile(0.95)(query_duration_ms)) AS p95_ms,
round(quantile(0.99)(query_duration_ms)) AS p99_ms,
countIf(exception_code != 0) AS failed,
formatReadableSize(sum(read_bytes)) AS read_total
FROM clusterAllReplicas('default', system.query_log)
WHERE event_time >= now() - INTERVAL 1 DAY
AND type IN ('QueryFinish', 'ExceptionWhileProcessing')
AND query_kind = 'Select'
GROUP BY
hour_bucket,
user
ORDER BY
hour_bucket,
p99_ms DESC;A ClickHouse Cloud performance SLO is only useful if it is owned. Each customer-facing service gets a named p99 target, an error budget and a review date. When the p99 burns through its budget, the response is engineering work on the top fingerprints, not a larger replica by default.
Codecs: a storage lever that also reduces I/O
On ClickHouse Cloud, storage is billed per compressed terabyte-month and backups at the same rate. Compressed bytes are also what every query has to read from object storage or cache. We measured three codec strategies on 30 million rows of synthetic device telemetry with an identical sort key. Only the column definitions differed:
CREATE TABLE finops.telemetry_tuned_v2
(
tenant_id UInt32 CODEC(T64, ZSTD(3)),
event_time DateTime CODEC(DoubleDelta, ZSTD(3)),
device_id UInt64 CODEC(ZSTD(3)),
metric_name LowCardinality(String) CODEC(ZSTD(3)),
metric_value Float64 CODEC(ZSTD(3)),
status_code UInt16 CODEC(T64, ZSTD(3))
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time)
ORDER BY (tenant_id, metric_name, event_time);
-- On ClickHouse Cloud the MergeTree engine is mapped to SharedMergeTree.
-- Measure the effect per column, before and after
SELECT
table,
name AS column,
formatReadableSize(data_compressed_bytes) AS compressed,
round(data_uncompressed_bytes / data_compressed_bytes, 1) AS ratio
FROM system.columns
WHERE database = 'finops'
AND table LIKE 'telemetry%'
ORDER BY
column,
table;Default codecs produced 189.8 MiB. The tuned table with Gorilla on the float column produced 107.0 MiB. The same table with plain ZSTD on the float produced 75.0 MiB, a 60.5 percent reduction against the default. The largest single gain came from DoubleDelta on event_time: 98.2 MiB fell to 161.8 KiB. The result we did not expect was Gorilla. On this noisy float series it compressed worse than plain ZSTD, at 92.3 MiB against 71.8 MiB for the default codec on that column. Codec advice that is not measured on the customer’s own data is a guess, and so is any ClickHouse Cloud performance claim made without a measurement.
Rollups: where they pay and where they do not
CREATE TABLE finops.telemetry_hourly
(
tenant_id UInt32,
metric_name LowCardinality(String),
hour_bucket DateTime,
samples AggregateFunction(count),
avg_value AggregateFunction(avg, Float64),
p95_value AggregateFunction(quantileTDigest(0.95), Float64)
)
ENGINE = AggregatingMergeTree
PARTITION BY toYYYYMM(hour_bucket)
ORDER BY (tenant_id, metric_name, hour_bucket);
CREATE MATERIALIZED VIEW finops.telemetry_hourly_mv
TO finops.telemetry_hourly
AS
SELECT
tenant_id,
metric_name,
toStartOfHour(event_time) AS hour_bucket,
countState() AS samples,
avgState(metric_value) AS avg_value,
quantileTDigestState(0.95)(metric_value) AS p95_value
FROM finops.telemetry_tuned_v2
GROUP BY
tenant_id,
metric_name,
hour_bucket;For a 30-day query across all tenants, EXPLAIN ESTIMATE put the raw table at 20,736,000 rows and the rollup at 720,000, which is 28.8 times fewer. Median latency fell from 579.0 ms to 300.4 ms. It fell by less than the row count because merging t-digest states costs CPU. For the same query scoped to one tenant, the raw table was already pruned to 49,152 rows by the sort key and ran in 5.3 ms. The rollup took 7.5 ms. A rollup earns its keep on wide scans, not on queries the sort key has already narrowed. That is the kind of distinction ClickHouse Cloud performance reviews exist to make.
Figure 2. Measured effect of two ClickHouse Cloud performance levers. Lab: chDB 4.4.0 embedding ClickHouse 26.9.2.1, 2 vCPU, 7 GB RAM, median of 7 runs. This is not a ClickHouse Cloud benchmark; the absolute latencies will differ on Cloud hardware.
Our commitment: every ClickHouse Cloud performance recommendation we make arrives with the EXPLAIN output, the before-and-after read_bytes and the p95 change that justify it.
Pillar two: ClickHouse Cloud scalability by design
On the Scale tier, ClickHouse Cloud scales vertically on its own and horizontally on request. Autoscaling is useful. It is not a scalability design. Without one, ingest, dashboards and ad-hoc analysis compete for the same replicas, and the autoscaler buys more memory to settle the argument.
Our default design uses ClickHouse Cloud warehouses, the compute-compute separation available on the Scale and Enterprise tiers. Several services share one copy of the data in object storage. Each service has its own replicas, size, autoscaling and idling. Read-only secondaries run no background merges, so all of their capacity goes to queries.
Figure 3. A warehouse layout that protects ClickHouse Cloud performance for customer-facing queries: ingest on the primary, dashboards and analysts on separate read-only services.
Separation is enforced with roles and settings profiles as well as endpoints. An analyst who connects to the wrong service still hits a ceiling:
CREATE SETTINGS PROFILE analyst_guardrails
SETTINGS
max_execution_time = 120,
max_bytes_to_read = 500000000000,
read_overflow_mode = 'throw',
max_result_rows = 1000000,
max_memory_usage = 20000000000
TO analyst_role;
-- Wide scans on large services: let replicas share the read.
-- Measure p95 before and after; parallel replicas add coordination overhead.
SELECT
metric_name,
avg(metric_value) AS avg_value
FROM finops.telemetry_tuned_v2
WHERE event_time >= now() - INTERVAL 90 DAY
GROUP BY metric_name
SETTINGS
enable_parallel_replicas = 1,
max_parallel_replicas = 3;We track three scalability signals monthly alongside ClickHouse Cloud performance percentiles: memory headroom per replica, the number of autoscaling events that reached the configured ceiling, and ingest lag at the daily peak against the agreed freshness SLO. A service that regularly reaches its ceiling is under-designed, not under-provisioned, and ClickHouse Cloud performance will degrade at the next peak.
Our commitment: scalability changes are checked against ClickHouse Cloud performance targets and against the invoice before they are applied, never after.
Pillar three: ClickHouse Cloud high availability you have rehearsed
The Scale tier spreads a service across two or more availability zones, and ClickHouse Keeper is operated by the vendor. Two facts from the published documentation shape our designs. Single-replica services are limited to small memory sizes, so a production service should run at least two replicas. The default backup policy is one backup every 24 hours, retained for one day, which is rarely enough for a regulated workload.
We check replica health from inside the service, then codify the backup policy so it cannot drift:
-- Every replica of the current service should answer
SELECT
hostName() AS replica,
uptime() AS uptime_seconds,
version() AS server_version
FROM clusterAllReplicas('default', system.one)
ORDER BY replica;# Terraform, ClickHouse provider. Values are an example policy, not a default.
# Plan and review in a non-production workspace before applying.
resource "clickhouse_service" "analytics_primary" {
name = "analytics-primary"
cloud_provider = "aws"
region = "us-east-1"
num_replicas = 3
min_replica_memory_gb = 16
max_replica_memory_gb = 64
idle_scaling = false
password_hash = var.ch_password_hash
ip_accesses = [
{ source = var.vpc_egress_cidr, description = "application VPC" }
]
backup_configuration = {
backup_period_in_hours = 6
backup_retention_period_in_hours = 720
}
}Backups run only from the primary service of a warehouse, and a restore creates a new service outside the warehouse. A restore is therefore a reconfiguration of endpoints and secondaries, not a single click. We rehearse it every quarter, record the restore time against the agreed RTO and the recovery point against the agreed RPO, and file the result with the customer. An untested backup is a hypothesis, not a recovery plan. Availability is the part of ClickHouse Cloud performance that users notice most when it fails.
Our commitment: a restore drill every quarter, with the measured RTO and RPO filed with the customer, and a backup policy held in code.
Pillar four: ClickHouse Cloud FinOps a CFO can audit
ClickHouse Cloud bills compute per compute unit (8 GiB of memory and 2 vCPU) per hour, metered per minute. It bills storage and backups per terabyte-month, and egress per gigabyte. The published ClickHouse Cloud list rates for AWS us-east-1 were USD 0.39030 per compute-unit-hour and USD 25.30 per TB-month when we checked on 5 November 2026. Prices change, so verify them before relying on any figure below.
Cost attribution comes from the billing API, not from estimates, and it sits next to the ClickHouse Cloud performance figures in the same monthly report. This read-only script pulls daily cost by entity and meter from the usageCost endpoint:
"""Daily ClickHouse Cloud cost by service and meter, from the usageCost API.
Read-only. Needs an API key with control-plane:organization:view.
Usage: CH_ORG_ID=... CH_KEY_ID=... CH_KEY_SECRET=... python3 usage_cost.py 2026-10-01 2026-10-31
"""
import os
import sys
from collections import defaultdict
import requests
API = "https://api.clickhouse.cloud/v1/organizations/{org}/usageCost"
def fetch(org_id, key_id, key_secret, from_date, to_date, tag=None):
params = {"from_date": from_date, "to_date": to_date} # max 31 days, UTC
if tag:
params["filter"] = [f"tag:{tag}"]
resp = requests.get(API.format(org=org_id), params=params,
auth=(key_id, key_secret), timeout=30)
resp.raise_for_status()
return resp.json()["result"]
def summarise(result):
by_entity = defaultdict(lambda: defaultdict(float))
for row in result["costs"]:
name = f'{row["entityType"]}:{row["entityName"]}'
for meter, value in (row.get("metrics") or {}).items():
by_entity[name][meter] += value or 0.0
by_entity[name]["totalCHC"] += row.get("totalCHC") or 0.0
return by_entity
if __name__ == "__main__":
result = fetch(os.environ["CH_ORG_ID"], os.environ["CH_KEY_ID"],
os.environ["CH_KEY_SECRET"], sys.argv[1], sys.argv[2],
tag=os.environ.get("CH_TAG_FILTER")) # e.g. Environment=Production
grand = result["grandTotalCHC"] or 1.0
rows = sorted(summarise(result).items(),
key=lambda kv: kv[1]["totalCHC"], reverse=True)
for name, m in rows:
print(f"{name[:48]:48} compute={m['computeCHC']:10.2f} "
f"storage={m['storageCHC']:9.2f} backup={m['backupCHC']:8.2f} "
f"share={100 * m['totalCHC'] / grand:5.1f}%")The illustrative model below uses the list compute rate above with the warehouse in Figure 3. The always-on column keeps every service awake for the whole month. The designed column keeps the primary always on, wakes the dashboard service fourteen hours a day, and wakes the analyst service six hours on 22 working days.
| Service (illustrative) | Compute units | Always on, USD/month | Designed, USD/month |
|---|---|---|---|
| Primary, 3 x 16 GiB | 6 | 1,709.51 | 1,709.51 |
| Dashboards, 2 x 32 GiB | 8 | 2,279.35 | 1,328.89 |
| Analysts, 1 x 64 GiB | 8 | 2,279.35 | 412.16 |
| Compute total | 22 | 6,268.22 | 3,450.56 |
| Storage, 10 TB compressed | n/a | 253.00 | 100.01 with lab codec ratio |
These figures are arithmetic on list prices, not a quote or a customer result. Two conclusions hold regardless of scale. Idling design removed 45 percent of compute spend in this model. Compute was more than twenty times storage, so a FinOps programme that starts with storage starts in the wrong place. The idling and the ceilings belong in code:
resource "clickhouse_service" "analysts" {
name = "analytics-adhoc"
warehouse_id = var.analytics_warehouse_id # warehouse of the primary service
readonly = true
cloud_provider = "aws"
region = "us-east-1"
num_replicas = 1
min_replica_memory_gb = 16
max_replica_memory_gb = 64 # spend ceiling: autoscaling stops here
idle_scaling = true
idle_timeout_minutes = 15 # minimum 5; trade cold starts against cost
password_hash = var.ch_password_hash
}Our twelve-metric ClickHouse Cloud FinOps scorecard covers the monthly metrics in detail, and the managed ClickHouse Cloud FinOps service runs them for customers.
Our commitment: cost is reported per service, per meter and per tag every month, and no saving is traded for ClickHouse Cloud performance the business has not agreed to give up.
What the commitment means in practice
| Cadence | What we deliver |
|---|---|
| Continuous | 24x7x365 support with an S1 response in 15 minutes, S2 in 12 hours, S3 in 24 hours and S4 in 48 hours |
| Monthly | ClickHouse Cloud performance and cost review: top fingerprints, p95 and p99 per service, cost by service and meter |
| Quarterly | Restore drill with measured RTO and RPO; warehouse and ceiling review; capacity forecast |
| Per release | Review of behaviour changes against the customer’s query history before the service’s upgrade window |
| At any time | An honest assessment of whether ClickHouse Cloud or self-managed open-source ClickHouse is the better fit, and a migration path in either direction |
The last line matters most to us. A long-term commitment to a customer’s ClickHouse Cloud performance is only credible if we are also prepared to say when Cloud is the wrong answer.
Where this guidance stops
The lab figures come from a single small node running the open-source engine through chDB, not from ClickHouse Cloud hardware. They show the mechanisms behind ClickHouse Cloud performance; they do not predict your latency or bill. The cost table is illustrative arithmetic on list prices that change. ClickHouse Cloud features, tiers and Terraform provider arguments also evolve, so confirm them against the vendor’s current documentation. Test every change on your own workload in a non-production service first, with a verified backup and a rehearsed restore behind it.
Engineer ClickHouse Cloud performance and cost for the long term
ChistaDATA architects review your ClickHouse Cloud performance, warehouse design, sort keys, codecs, backup policy and invoice against measured evidence, then stay on to operate what they recommend, 24x7x365.
Running ClickHouse in production? ChistaDATA provides ClickHouse consulting for architecture, performance and migrations, and 24×7 ClickHouse support with a 15-minute S1 response. For day-to-day operations see ClickHouse DBA services and ClickHouse managed services.