Micro-partitions, pruning and clustering

Snowflake · Advanced · 15 min

Pruning is the main reason Snowflake queries are fast or slow on large tables.

Every table is stored as micro-partitions: immutable files holding about 50 to 500 MB of uncompressed data each, stored column by column. For each micro-partition and column Snowflake keeps metadata such as min and max values, distinct counts and null counts.

When a query filters (WHERE event_date = '2025-06-01'), the optimizer compares the filter to that metadata and prunes micro-partitions that cannot contain matches, before reading anything. In the query profile, the TableScan node shows "Partitions scanned" versus "Partitions total"; that ratio is the first thing to check on a slow query.

Pruning works only if matching values are concentrated in few micro-partitions. Data loaded in time order is naturally well clustered by time. Data that arrives randomly, or a filter on a column unrelated to load order, spreads values across every micro-partition.

A clustering key (ALTER TABLE t CLUSTER BY (event_date, tenant_id)) tells Snowflake to reorganize data in the background (Automatic Clustering) so similar values sit together. Consider it when:

  • the table is large (multi-terabyte, or many thousands of micro-partitions),
  • queries filter on the same columns most of the time and prune poorly,
  • the table isn't rewritten constantly, since churn makes reclustering expensive.

Automatic Clustering consumes credits. Measure with SYSTEM$CLUSTERING_INFORMATION, where a lower average_depth is better. Use low-to-medium-cardinality columns or expressions like TO_DATE(ts) rather than raw timestamps or ids.

Example

-- How well is the table clustered on the column we filter by?
SELECT SYSTEM$CLUSTERING_INFORMATION('events', '(TO_DATE(event_ts))');
-- {"cluster_by_keys": "LINEAR(TO_DATE(event_ts))",
--  "total_partition_count": 48211, "average_depth": 812.4, ...}   <- poor

ALTER TABLE events CLUSTER BY (TO_DATE(event_ts), tenant_id);

-- Later: depth drops as Automatic Clustering works in the background
SELECT SYSTEM$CLUSTERING_INFORMATION('events');

-- Check pruning for a typical query in the query profile:
--   TableScan: Partitions scanned 112 / Partitions total 48211
SELECT tenant_id, COUNT(*) FROM events
WHERE event_ts >= '2025-06-01' AND event_ts < '2025-06-02'
GROUP BY tenant_id;

-- Pause reclustering (and its credit use) if needed
ALTER TABLE events SUSPEND RECLUSTER;

Remember

  • Micro-partition min/max metadata lets Snowflake prune before reading
  • Check partitions scanned vs total in the query profile
  • Clustering keys pay off on large, frequently filtered, rarely rewritten tables

Watch out for

  • Clustering by a high-cardinality column such as a raw timestamp or UUID, which is costly to maintain and prunes little.

Check yourself

  1. A query on a 30 TB table scans 47,000 of 48,000 partitions despite a selective date filter. What is the likely cause?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.snowflake.com/en/user-guide/tables-clustering-keys