Both systems can prune. The difference is how precisely they isolate the matching data, how that holds up as new query patterns appear, and what it costs to hold a latency SLO as traffic grows.
Example: 12 days of transactions, about 2.36 million rows. ClickHouse uses daily parts sorted by category and event time; StarTree uses daily segments with time routing and per-column indexes. Both queries cover the last 7 days, which is 168 granules of 8,192 rows.
Stage 1, dashboard query on the sort key (category = 'electronics'): ClickHouse keeps 4 granules a day, 28 granules or 229,376 candidate rows, to find 172,032 matching rows. StarTree's inverted index on category and range index on event_time return only the 172,032 matching rows.
Stage 2, customer lookup (customer_id = 734521, not in the sort key): with a bloom filter skip index, ClickHouse keeps 9 granules (5 with a match plus 4 false positives), 73,728 candidate rows, to find 5 transactions. With a projection by customer_id it keeps 5 granules, 40,960 rows. StarTree's inverted index returns the 5 rows.
Stage 3, 90% lookups and 10% dashboard queries at rising QPS: ClickHouse with a bloom filter does about 5.2 times the modeled CPU work per query (about 37.4 versus 7.2 CPU-ms). Using a 70% operating limit to preserve headroom under a fixed p99 SLO, ClickHouse needs 4 nodes at 1,000 QPS while StarTree stays within the limit on 1 node. If ClickHouse uses a projection by customer_id instead, it does about 3.5 times the modeled work and needs 3 nodes. Illustrative model, not benchmark results.
Illustrative model assumes the same modeled CPU cost per candidate row across both systems and both query shapes, so CPU work scales directly with candidate rows left after pruning. It isolates pruning precision, not operator or per-row execution efficiency. Capacity values are explanatory, not benchmark results.
events(event_time, customer_id, category, amount), where customer_id is high-cardinality. ClickHouse: daily parts, ORDER BY (category, event_time). StarTree: daily segments with time routing and per-column indexes. 12 days × 24 granules a day × 8,192 rows = about 2.36M transactions (synthetic, the same every run). The query window is the last 7 days: 7 × 24 = 168 granules. For simplicity, the animation assumes the 7-day window is aligned to daily partition boundaries.category and range index on event_time return only the electronics rows, without relying on that sort order: 7 × 3 × 8,192 = 172,032 rows.GRANULARITY 1 in this example): the 5 granules that contain a match + 4 assumed false positives (an illustrative ~2.5% false-positive outcome) = 9 × 8,192 = 73,728 rows. Projection by customer_id: one granule per matching day = 5 × 8,192 = 40,960 rows. StarTree: the 5 rows.