Quand une requête est très lente dans Snowflake, le premier réflexe est souvent d'augmenter la warehouse ou simplement d'accuser les données et accepter cela. Mais parfois, le vrai problème est ailleurs, dans l'organisation physique des données au niveau des micro-partitions.

Si ta requête scanne toute la table, une warehouse plus grosse ne fera que scanner tout plus vite… et plus cher. Le problème n'est donc pas la puissance de calcul, c'est le volume de données lues.

Petit rappel sur les micro-partitions

💡
Si tu ne sais pas c'est quoi les micro-partitions, je te conseille de lire d'abord mon article sur l'architecture snowflake

Dans Snowflake, toutes les tables sont découpées automatiquement en micro-partitions (petites unités de stockage d'environ 50 à 500MB avant compression) et donc chaque micro-partition embarque des métadonnées comme min/max des valeurs, nombre de valeurs distinctes, etc...

C'est grâce à ces métadonnées que Snowflake peut éliminer des micro-partitions entières sans les lire. Par exemple, si tu filtres sur WHERE order_date = '2024-01-15', Snowflake regarde les métadonnées de chaque partition, et ne lit que celles qui contiennent potentiellement cette date.

C'est quoi concrètement le clustering ?

Pour simplifier le clustering permet de dire à Snowflake : "organise les données selon telle colonne (ou telles colonnes)" pour que les valeurs similaires se retrouvent dans les mêmes micro-partitions et donc quand tu filtres sur cette colonne, Snowflake peut éliminer facilement beaucoup plus de partitions avant même de lire les données. Au lieu de scanner 1000 partitions, il en lit 50. Et ça, ça change tout.

Comment Snowflake organise les micro-partitions par défaut

Avant de parler de clustering keys, il faut comprendre comment Snowflake organise les données sans intervention.

Et on va prendre un exemple pour bien comprendre le mécanisme :

COPY INTO orders
FROM @my_stage/orders_2024.csv;

COPY INTO orders
FROM @my_stage/orders_2025.csv;

COPY INTO orders
FROM @my_stage/orders_2026.csv;

Si tu charges d'abord toutes les commandes de 2024, puis celles de 2025, puis celles de 2026, les micro-partitions vont naturellement avoir toutes les dates de 2024 regroupées, puis toutes celles de 2025, puis toutes celles de 2026.

Mais si tu fais des INSERT réguliers avec des données mélangées (par exemple des commandes de différentes régions qui arrivent en continu), Snowflake ne peut pas deviner que tu vas filtrer plus tard par région et donc chaque partition va contenir un mix de plusieurs régions.

Quand tu filtreras sur region = 'Europe', Snowflake devra lire toutes les partitions qui contiennent au moins une ligne Europe. Et ça peut être beaucoup.

💡
C'est là que le clustering devient utile car tu indiques à Snowflake comment réorganiser les données pour que chaque partition contienne principalement une seule région (ou une seule plage de dates, etc....).

Qu'est-ce qu'une clustering key ?

Maintenant qu'on a vu ce qu'est le clustering et pourquoi c'est important, voyons comment ça marche concrètement. Une clustering key, c'est une ou plusieurs colonnes que tu définis pour dire à Snowflake : "organise les micro-partitions en fonction de ces colonnes".

Snowflake va alors :

  • Regrouper les lignes qui ont des valeurs similaires dans ces colonnes
  • Les placer dans les mêmes micro-partitions
  • Mettre à jour les métadonnées pour que Snowflake puisse ignorer plus de partitions lors des lectures

Exemple :

ALTER TABLE orders 
CLUSTER BY (order_date);

À partir de ce moment, Snowflake va progressivement réorganiser la table pour que les commandes d'une même date se retrouvent dans les mêmes partitions.

💡
Le clustering n'est pas instantané. Snowflake réorganise les données en arrière-plan via un processus appelé Automatic Clustering (si activé).

C'est quoi le Automatic Clustering ?

Par défaut, quand tu définis une clustering key, Snowflake active l'Automatic Clustering. En réalité, c'est tous simplement un service qui tourne en arrière-plan et qui réorganise les micro-partitions quand elles sont trop désordonnées.

Snowflake mesure le désordre avec un indicateur appelé Clustering Depth. Et plus le clustering depth est élevé, plus les données sont dispersées.

Tu peux vérifier l'état du clustering avec cette requête :

SELECT SYSTEM$CLUSTERING_INFORMATION('orders', '(order_date)');

Le résultat te donne plusieurs infos :

{
  "cluster_by_keys" : "(order_date)",
  "total_partition_count" : 1245,
  "total_constant_partition_count" : 0,
  "average_overlaps" : 12.4,
  "average_depth" : 12.4,
  "partition_depth_histogram" : {
    "00000" : 0,
    "00001" : 120,
    "00002" : 340,
    ...
  }
}

Ce qu'il faut regarder :

  • average_depth : le nombre moyen de partitions qui se chevauchent pour une même valeur. Et plus c'est bas, mieux c'est.
  • partition_depth_histogram : la distribution des partitions selon leur profondeur. Idéalement, tu veux beaucoup de partitions avec depth = 1 ou 2.

Si le average_depth est élevé, ça veut dire que le clustering n'est pas bon et qu'il y a beaucoup de chevauchement entre partitions.

⚠️
Attention car l'automatic Clustering consomme des crédits et donc ça peut coûter cher sur de très grosses tables. Tu peux suspendre l'automatic clustering avec SUSPEND RECLUSTER si besoin.

Exemple concret : impact du clustering sur une requête

On reprend la table ORDERS de mon article sur le Query Profile. Cette fois, on va créer une copie sans clustering, puis une autre avec clustering sur O_ORDERDATE.

-- Table sans clustering
CREATE TABLE orders_no_cluster AS
SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF100.ORDERS;

-- Table avec clustering
CREATE TABLE orders_with_cluster AS
SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF100.ORDERS;

ALTER TABLE orders_with_cluster 
CLUSTER BY (O_ORDERDATE);

Maintenant, on lance la même requête sur les deux tables :

-- Sans clustering
SELECT COUNT(*) AS nb_orders_1996
FROM orders_no_cluster
WHERE O_ORDERDATE >= '1996-01-01'
  AND O_ORDERDATE <  '1997-01-01';

-- Avec clustering
SELECT COUNT(*) AS nb_orders_1996
FROM orders_with_cluster
WHERE O_ORDERDATE >= '1996-01-01'
  AND O_ORDERDATE <  '1997-01-01';

Résultats dans le Query Profile :

Sans clustering :

  • Partitions scannées : 291 / 291 (100%)
  • Bytes scannés : 1.2 GB
  • Temps : 2.2s

Avec clustering :

  • Partitions scannées : 18 / 291 (6%)
  • Bytes scannés : 80 MB
  • Temps : 0.4s

Le clustering a permis à Snowflake d'éliminer 94% des partitions. Résultat, la requête est 8 fois plus rapide et lit 15 fois moins de données.

💡
Ici, le clustering est vraiment utile parce qu'on filtre souvent sur O_ORDERDATE et que cette colonne a une bonne cardinalité (beaucoup de valeurs différentes bien réparties).

Quand utiliser une clustering key

Le clustering n'est pas une solution magique. Il faut l'utiliser dans des cas bien précis.

Utilise le clustering quand :

  • Le Query Profile montre que Snowflake scanne beaucoup trop de partitions
  • Tu as une grosse table (plusieurs GB ou TB)
  • Tu filtres souvent sur une ou deux colonnes spécifiques
  • La colonne a une bonne cardinalité (dates, IDs, catégories avec plusieurs valeurs distinctes...)

Ne perds pas ton temps avec le clustering si :

  • La table est petite
  • Tu filtres sur des colonnes qui changent tout le temps
  • La colonne a une cardinalité trop faible (2-3 valeurs distinctes) ou trop haute (colonnes uniques comme un UUID ou un autonumber)

Un point important à ne pas oublier "une table" = "une seule clustering key".

Choisir la bonne clustering key

Le choix de la clustering key est trés important car un mauvais key peut ne rien apporter, voire dégrader les performances.

Règle 1 : Priorise les colonnes de filtre

La meilleure clustering key est souvent la colonne que tu utilises le plus dans tes WHERE. Par exemple order_date ou customer_id

Règle 2 : Attention à la cardinalité

Comme mentionné précédemment une Cardinalité trop faible (ex: 2-5 valeurs) n'apporte presque rien. Snowflake va créer quelques grosses partitions par valeur, mais le gain est négligeable.

Cardinalité trop élevée (ex: UUID unique par ligne) et la le clustering va créer une infinité de petites partitions et ça ne sert à rien.

Cardinalité idéale c'est entre Entre 100 et 100 000 valeurs distinctes. Les dates, les IDs clients, les catégories produits marchent généralement bien.

Règle 3 : Les clustering keys composites (plusieurs colonnes)

Tu peux définir plusieurs colonnes dans une clustering key :

ALTER TABLE orders 
CLUSTER BY (region, order_date);

Snowflake va d'abord organiser par region, puis par order_date à l'intérieur de chaque région.

Ordre d'importance : Mets en premier la colonne avec la plus faible cardinalité vers la plus forte

⚠️
Attention car plus tu ajoutes de colonnes dans la key, plus le clustering devient complexe et coûteux. En général, il est recommandé de ne pas dépasser 3-4 colonnes.

Automatic Clustering

L'Automatic Clustering est pratique, mais il peut coûter cher si tu ne fais pas attention.

Voir les coûts de clustering

SELECT *
FROM TABLE(INFORMATION_SCHEMA.AUTOMATIC_CLUSTERING_HISTORY(
  DATE_RANGE_START => DATEADD('day', -7, CURRENT_DATE())
))
ORDER BY START_TIME DESC;

Cette requête te montre :

  • Combien de crédits ont été consommés
  • Combien de données ont été réorganisées
  • Combien de partitions ont été touchées

Suspendre le reclustering

Si les coûts montent trop, tu peux suspendre temporairement l'automatic clustering :

ALTER TABLE orders SUSPEND RECLUSTER;

Pour le réactiver :

ALTER TABLE orders RESUME RECLUSTER;

Les pièges à éviter

Piège 1 : Clustériser toutes les tables

Encore une fois le clustering a un coût. Si tu l'actives partout et au cas où, tu vas payer pour rien. Garde-le pour les vraies grosses tables où le pruning fait une vraie différence.

Piège 2 : Changer trop souvent de clustering key

Chaque fois que tu changes la clustering key, Snowflake doit réorganiser toute la table. Ça peut prendre du temps et consommer beaucoup de crédits.

Choisis bien ta key dès le départ, et ne la change que si tu as une vraie raison (changement de pattern de requêtes, nouvelle colonne de filtre dominante).

Piège 3 : Clustériser des tables qui changent tout le temps

Si ta table reçoit des milliers d'INSERT ou UPDATE par jour, le clustering va constamment réorganiser les données. Ça peut coûter très cher.

Dans ce cas, préfère une stratégie de partitionnement applicatif (charger dans des tables séparées par date ou région, puis utiliser des vues pour les réunir).

Piège 4 : Ignorer le Query Profile

Avant de clustériser une table, regarde d'abord le Query Profile. Si le problème n'est pas lié au nombre de partitions scannées, le clustering ne servira à rien.

Par exemple, si ta requête est lente à cause de :

  • Gros calculs (CPU bound)
  • Beaucoup de jointures ou d'agrégations
  • Trop de colonnes lues (pas de filtres)

Dans ce genre de cas le clustering n'aidera pas beaucoup. Il faut optimiser autrement (revoir la requête, réduire les colonnes lues, etc....).

Au final, le clustering est un levier puissant, mais il ne remplace pas une bonne compréhension de tes données et de tes requêtes. Commence toujours par analyser le Query Profile avant de clustériser.

Aller plus loin : Formation Snowflake

J'ai regroupé tous mes articles Snowflake dans un parcours complet.

👉 Le parcours complet (articles + pratique)

Vous voulez que je vous accompagne sur votre projet data (Snowflake, ingestion, modélisation, performance, coûts, gouvernance) ?
👉 Réserver un appel de 30 minutes