Le clustering trie les données dans les blocs de stockage selon jusqu’à quatre colonnes. Cela permet l’élagage au niveau des blocs — BigQuery maintient des métadonnées sur les plages de valeurs dans chaque bloc et ignore les blocs qui ne peuvent pas contenir de lignes correspondantes. C’est une optimisation plus flexible que le partitionnement, avec moins de contraintes et un éventail plus large de cas d’usage.
La différence clé avec le partitionnement : le clustering ne crée pas de divisions physiques dans votre table. Là où le partitionnement donne des frontières strictes (une partition est soit scannée, soit elle ne l’est pas), le clustering fournit une optimisation probabiliste. BigQuery examine les métadonnées des blocs et ignore les blocs dont la plage de valeurs ne chevauche pas votre filtre. Plus vos données sont triées, plus de blocs peuvent être ignorés.
Comment Ça Fonctionne en Interne
BigQuery utilise une approche similaire à un arbre LSM pour maintenir le clustering. Cela se connecte directement à la séparation stockage/calcul dans l’architecture de BigQuery.
Quand de nouvelles données arrivent — via des insertions en streaming, des chargements batch ou des opérations DML — elles atterrissent dans des blocs « delta » triés localement. Ces blocs sont triés selon vos colonnes de clustering, mais ils existent indépendamment des données existantes. Un processus en arrière-plan fusionne continuellement ces blocs delta en blocs « baseline » entièrement triés.
Le détail crucial : le re-clustering automatique se produit sans frais. Pas de consommation de slots, pas de facturation. BigQuery gère cela comme une opération de maintenance en arrière-plan. Vous n’avez pas besoin d’exécuter OPTIMIZE ou de planifier des jobs de maintenance. C’est un avantage significatif par rapport à des systèmes comme Databricks Delta Lake, où OPTIMIZE est une opération explicite qui consomme du calcul.
Cela signifie que vous pouvez ajouter du clustering à une table et l’oublier. Les données restent triées automatiquement à mesure que de nouvelles lignes arrivent, et l’optimisation s’améliore au fil du temps à mesure que le processus en arrière-plan fusionne plus de blocs.
L’Ordre des Colonnes Est Crucial
BigQuery trie les données hiérarchiquement selon vos colonnes de clustering dans l’ordre. C’est la chose la plus importante à comprendre sur le clustering — et la source des erreurs les plus courantes.
Les requêtes ne bénéficient du clustering que lorsqu’elles filtrent sur un préfixe des colonnes de clustering. Si vous clusterisez par [region, customer_id, product_id] :
- Filtre sur
regionseul —> optimisé (première colonne du préfixe) - Filtre sur
regionETcustomer_id—> optimisé (deux premières colonnes) - Filtre sur
regionETcustomer_idETproduct_id—> entièrement optimisé (toutes les trois) - Filtre sur
customer_idseul, en sautantregion—> non optimisé - Filtre sur
product_idseul —> non optimisé
Cette exigence de préfixe découle du fonctionnement du tri hiérarchique. Les données sont triées par région en premier, puis dans chaque région par customer_id, puis dans chaque customer_id par product_id. Rechercher par customer_id sans région revient à chercher un mot dans un dictionnaire trié d’abord par langue — il faudrait vérifier chaque section de langue.
Définir le Bon Ordre
Placez votre colonne la plus fréquemment filtrée en premier. Ne devinez pas — vérifiez vos patterns de requêtes réels :
-- Trouver quelles colonnes apparaissent le plus souvent dans les clauses WHERESELECT referenced_tables.table_id, REGEXP_EXTRACT_ALL(query, r'WHERE.*?(\w+)\s*[=<>]') AS filter_columns, COUNT(*) AS query_countFROM `region-us`.INFORMATION_SCHEMA.JOBS,UNNEST(referenced_tables) AS referenced_tablesWHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY) AND job_type = 'QUERY'GROUP BY 1, 2ORDER BY query_count DESC;En pratique, l’ordre correct suit souvent les patterns de drill-down naturels dans votre domaine. Pour les données d’événements, c’est généralement event_name puis user_id. Pour les SaaS multi-tenants, c’est tenant_id en premier. Pour les données marketing, cela suit la hiérarchie des campagnes : campaign_id, puis ad_group_id, puis ad_id.
La Limite de Quatre Colonnes
Vous pouvez clusteriser par au plus quatre colonnes. C’est rarement une contrainte en pratique — la plupart des tables ont 1 à 3 patterns de filtres dominants. Si vous vous retrouvez à vouloir plus de quatre colonnes de clustering, il vaut la peine de se demander si la table n’essaie pas de servir trop de cas d’usage. Envisagez de la diviser en vues matérialisées ou marts spécifiques à chaque usage.
Clustering vs Partitionnement : Quand Choisir le Clustering
Le clustering résout des problèmes que le partitionnement ne peut pas :
Plusieurs colonnes de filtre sans dominante unique. Si les requêtes filtrent sur user_id, product_id, region et status dans diverses combinaisons, le clustering gère cela. Le partitionnement nécessite de choisir une colonne.
Colonnes à haute cardinalité. Les colonnes comme user_id ou session_id ont des millions de valeurs distinctes. Le partitionnement atteindrait immédiatement la limite de 10 000 partitions. Le clustering gère la haute cardinalité avec élégance parce qu’il opère au niveau des blocs, pas des partitions.
Tables trop petites pour des partitions significatives. Les tables dans la plage 64 Mo à 10 Go bénéficient de l’élagage au niveau des blocs mais n’ont pas assez de données pour justifier la surcharge des métadonnées de partitions. Voir le cadre de décision pour les seuils de taille exacts.
Le partitionnement créerait de minuscules partitions. Si votre volume de données quotidien est de 100 Mo, les partitions quotidiennes sont gaspilleuses — chaque partition est trop petite pour que BigQuery puisse l’optimiser, et la surcharge de métadonnées s’accumule. Le clustering fournit une réduction de scan sans la surcharge des partitions.
Ce que le Clustering Ne Vous Donne Pas
Comprendre ce qui manque au clustering par rapport au partitionnement aide à choisir le bon outil :
Pas d’estimations de coût pré-exécution prévisibles. Les bénéfices du clustering n’apparaissent pas dans les estimations de dry-run. Un dry run peut estimer 50 Go pour une requête, mais le scan réel est de 5 Go grâce à l’élagage de clusters. Vous ne pouvez pas connaître le coût réel avant l’exécution de la requête. Si la prévisibilité des coûts avant exécution compte pour votre équipe, le partitionnement le fournit.
Pas de gestion du cycle de vie. Vous ne pouvez pas expirer automatiquement des données clusterisées, supprimer des plages efficacement, ou écrire dans des segments spécifiques sans toucher les autres. Ces capacités nécessitent le partitionnement.
Pas de support insert_overwrite. La stratégie insert_overwrite dans dbt nécessite des partitions. Si vous utilisez uniquement le clustering (sans partitionnement), vous êtes limité aux stratégies merge ou append pour les modèles incrémentaux.
Pas d’application de filtre. Il n’y a pas d’équivalent de require_partition_filter pour le clustering. Vous ne pouvez pas empêcher les analystes d’exécuter des requêtes qui ne filtrent pas sur les colonnes de clustering.
Clustering avec dbt
Dans dbt, le clustering est configuré avec le paramètre cluster_by :
{{ config( materialized='table', cluster_by=['user_id', 'event_name']) }}Ou combiné avec le partitionnement pour les grandes tables :
{{ config( materialized='incremental', partition_by={ 'field': 'event_date', 'data_type': 'date', 'granularity': 'day' }, cluster_by=['event_name', 'user_pseudo_id', 'traffic_source']) }}Lors de l’utilisation de la stratégie incrémentale merge, le clustering améliore significativement les performances de merge en réduisant les lignes que BigQuery doit comparer. Clusterisez sur vos colonnes unique_key lors de l’utilisation de merge — cela garantit que la jointure MERGE peut tirer parti de l’élagage au niveau des blocs sur la table de destination.
Mesurer l’Efficacité du Clustering
Comme les dry runs ne reflètent pas les bénéfices du clustering, vous devez vérifier les performances réelles des requêtes. Comparez total_bytes_billed avec la taille totale de la table pour des requêtes représentatives :
SELECT job_id, total_bytes_billed, total_bytes_processed, ROUND(total_bytes_billed / POW(1024, 3), 2) AS gb_billedFROM `region-us`.INFORMATION_SCHEMA.JOBSWHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY) AND referenced_tables IS NOT NULLORDER BY total_bytes_billed DESCLIMIT 20;Si vous scannez plus de 5 à 10 % d’une grande table clusterisée sur des requêtes avec les filtres appropriés, le clustering n’est pas efficace. Vérifiez que vos requêtes filtrent sur un préfixe des colonnes de clustering, pas seulement sur n’importe quelle colonne de clustering. Voir BigQuery Partition Pruning Patterns pour l’approche de mesure complète.
Sur une table bien conçue avec une configuration partition + cluster appropriée, vous pourriez scanner 10 à 100 Go sur une table de 10 To. C’est 100 à 1 000 fois moins de données facturées, se traduisant directement par des coûts inférieurs avec la tarification on-demand.