At a glance
The count of currently active (un-merged, live) data parts on each MergeTree table, ranked highest first. In ClickHouse, every insert writes a new part on disk, and a background process merges small parts into larger ones over time. When inserts outrun merges, parts pile up. A single table carrying more than 1,000 active parts is a merge-backlog warning, and once a partition crosses the configured cap it throws the TOO_MANY_PARTS error (code 252), which halts ingest on that table. This card is the early-warning view: it shows the backlog building before it breaks anything.
Calculation
The engine runs a grouped count againstsystem.parts, the system table that exposes one row per data part on the instance:
WHERE active clause is load-bearing. system.parts retains rows for inactive parts (parts that have been merged away but not yet physically deleted), and counting those would massively overstate the backlog. Only active = 1 parts are live and only they count toward the parts_to_throw_insert cap that triggers code 252.
The threshold of 1,000 is deliberately below the hard cap. ClickHouse starts to delay inserts (the parts_to_delay_insert soft limit, default 150 per partition) long before it throws. By the time a table sustains 1,000+ active parts across its partitions, the merge scheduler is demonstrably not keeping up, and the prudent action is to reduce insert frequency or increase merge throughput, not to wait for the hard error.
Worked example
A platform team runs a self-managed ClickHouse cluster behind an analytics pipeline that ingests clickstream and order events for several storefronts. Snapshot taken on 14 Apr 26 at 09:40 BST during a marketing-driven traffic surge.
The Nerve Centre headline reads 1,284 active parts on
events.clickstream_raw, outlined amber because it breaches the 1,000 threshold. The DBA reads three things:
clickstream_rawis the offender. 1,284 parts against 412M rows means roughly 320,000 rows per part: small, frequent inserts. The ingest job is almost certainly inserting per-event or per-tiny-batch rather than batching.- It is the only table over threshold.
order_eventsat 612 is climbing but has runway;pageview_agghas only 144 parts despite holding 1.9B rows because it is fed by large batched inserts. This contrast is the diagnosis: the problem is insert shape, not data volume. - The clock is running. At the current rate the partition will reach
parts_to_throw_insertwithin the hour, after which ingest on that table stops with code 252 and the Too Many Parts Errors (24h) counter starts climbing.
async_insert=1) so each insert creates one substantial part rather than dozens of tiny ones. Raising background_pool_size buys time but does not address a pipeline that fundamentally over-inserts.
Three takeaways:
- Part count, not row count, is what breaks ingest. A table with billions of rows in 144 parts is healthy; a table with 400M rows in 1,284 parts is in danger. Always read the part count, not the data size.
- The top offender is almost always an insert-shape problem. Frequent small inserts are the classic cause. Batching at the source resolves it permanently; tuning merges only buys time.
- This card is the leading indicator for Too Many Parts Errors (24h). Act while this card is amber and the error counter stays at zero.
Sibling cards
Reconciling against the source
Where to look in ClickHouse’s own tooling:Run the same query the card uses againstWhy our number may legitimately differ from a manual query:system.partsfromclickhouse-client:Inspect the soft and hard caps withSELECT * FROM system.merge_tree_settings WHERE name IN ('parts_to_delay_insert','parts_to_throw_insert','max_parts_in_total'). Watch live merge activity insystem.mergesand the pending-mutation/merge picture insystem.replicasfor replicated tables. On ClickHouse Cloud, the samesystem.partsquery works in the SQL console; the managed service also surfaces part-count health in its monitoring view.
Cross-connector reconciliation:
Known limitations / FAQs
Why is one table showing thousands of parts but the table is small in bytes? Part count is driven by how often you insert, not how much data you insert. Thousands of small inserts create thousands of small parts regardless of total size. Batch your inserts (aim for parts of at least a few hundred thousand rows) or enableasync_insert so the server buffers small inserts into larger parts before writing.
Is 1,000 parts a hard limit?
No. 1,000 is the card’s warning threshold, set deliberately below the engine’s caps. The real soft limit is parts_to_delay_insert (default 150 per partition, after which inserts are throttled) and the hard limit is parts_to_throw_insert (default 300 per partition, after which inserts throw code 252). Because those caps are per partition, a table spread across many partitions can hold well over 1,000 active parts in total, so the card’s table-level threshold is an aggregate early warning, not the exact failure point.
The count keeps changing every time I refresh. Is the card wrong?
No. system.parts reflects live state and ClickHouse merges parts continuously in the background. On a busy table the active-part count naturally fluctuates by a few parts second to second as merges complete and new inserts land. The trend matters more than any single reading: a count that is rising over minutes is the signal, not the exact value.
I ran the same query and got a higher number than the card.
The most common cause is omitting WHERE active. system.parts keeps rows for inactive (merged-away) parts until they are physically cleaned up, and those should not be counted. The second most common cause on clusters is replica scope: the card aggregates the configured node, so a query against a single replica with clusterAllReplicas may show different totals.
Does this apply to all my tables or only MergeTree?
Only MergeTree-family tables (MergeTree, ReplicatedMergeTree, ReplacingMergeTree, and the rest) have parts. Engines like Log, Memory, and Distributed do not create parts and never appear on this card. The vast majority of analytical workloads use the MergeTree family, so in practice this covers what matters.
What is the fastest safe way to clear a backlog right now?
First, reduce or pause the inflow if you can, this stops the bleeding. Second, increase merge concurrency by raising background_pool_size so more merges run at once. Only as a last resort run OPTIMIZE TABLE ... FINAL on the affected partition: it forces a full merge but is I/O-heavy and can compete with live queries, so target a single partition during a quiet window rather than the whole table.
On ClickHouse Cloud, do I still need to watch this?
Yes. ClickHouse Cloud manages the infrastructure but does not change the physics of parts and merges. An ingest job that inserts in tiny batches will accumulate parts and can still hit TOO_MANY_PARTS on Cloud. The same system.parts query works in the Cloud SQL console, and the same fix (batch at the source or use async inserts) applies.