Optimiser les requêtes pour l’actualisation incrémentielle¶
Utilisez cette page lorsque vous concevez une nouvelle requête de table dynamique ou que vous souhaitez optimiser une requête existante pour une actualisation incrémentielle. Ce guide montre quels opérateurs fonctionnent bien, qui nécessitent un traitement prudent, et comment restructurer les requêtes pour améliorer les performances.
Pour une liste complète des constructions de requête prises en charge pour l’actualisation incrémentielle, voir Requêtes prises en charge pour les tables dynamiques.
Attentes en matière de performances par opérateur¶
Avant d’optimiser une requête de table dynamique, comprenez quels opérateurs bénéficient de l’actualisation incrémentielle et lesquels peuvent causer des problèmes.
Note
Les requêtes courtes (moins de 10 secondes) peuvent présenter des gains de performances plus faibles en raison de frais généraux fixes tels que l’optimisation des requêtes et la planification des entrepôts.
Opérateurs qui fonctionnent toujours bien¶
Ces opérateurs fonctionnent efficacement avec une actualisation incrémentielle :
SELECTWHEREFROM<base table>UNION ALLQUALIFY[RANK|ROW_NUMBER|DENSE_RANK] … = 1
Pour plus de détails sur la façon dont Snowflake traite chaque opérateur, voir la table de référence des opérateurs.
Opérateurs concernés par la localité des données¶
Pour ces opérateurs, la performance dépend de la localité des données, qui correspond à la manière d’organiser vos données et à l’endroit où les changements se produisent par rapport à vos clés :
INNER JOINOUTER JOINGROUP BYDISTINCTOVER(fonctions de fenêtre)
Lorsque les modifications n’affectent qu’une petite partie des clés de regroupement ou de partition, ces opérateurs fonctionnent bien. Une faible localité des données ou des modifications réparties sur de nombreuses clés peuvent rendre l’actualisation incrémentielle plus lente par rapport à l’actualisation complète.
Pour plus de détails sur la façon dont Snowflake traite chaque opérateur, voir la table de référence des opérateurs.
Modèles d’optimisation courants¶
Les sections suivantes présentent des modèles communs pour optimiser les requêtes qui utilisent des opérateurs sensibles à la localité.
Optimiser les agrégations¶
Lorsque vous utilisez GROUP BY, Snowflake recalcule les agrégats pour chaque clé de regroupement contenant des modifications. Les performances dépendent des facteurs suivants :
Clustering de données : Les données sources regroupées par clés de regroupement sont les plus performantes.
Modifier la distribution : Visez des changements qui affectent moins de 5 % des clés de regroupement.
Complexité des clés : Les références de colonnes simples sont plus performantes que les expressions composées.
Problème : expressions composées dans les clés de regroupement¶
Cette requête fonctionne mal car la clé de regroupement est une expression :
CREATE DYNAMIC TABLE hourly_sums
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT DATE_TRUNC('minute', ts), SUM(amount)
FROM transactions
GROUP BY 1;
Solution : matérialiser l’expression¶
Fractionner en deux tables dynamiques pour exposer une clé de regroupement simple :
CREATE DYNAMIC TABLE transactions_with_minute
TARGET_LAG = DOWNSTREAM
WAREHOUSE = my_warehouse
AS
SELECT DATE_TRUNC('minute', ts) AS ts_minute, amount
FROM transactions;
CREATE DYNAMIC TABLE hourly_sums
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT ts_minute, SUM(amount)
FROM transactions_with_minute
GROUP BY 1;
Maintenant GROUP BY fonctionne sur une colonne simple, et la table intermédiaire bénéficie d’une meilleure localité des données.
Optimiser les jointures¶
La performance de la jointure dépend des changements de côté et de la manière de regrouper les données.
INNER JOIN : Snowflake joint les modifications du côté gauche à la table de droite, puis joint les modifications du côté droit à la table de gauche. Les jointures fonctionnent bien lorsqu’un côté est petit ou change peu souvent.
OUTER JOIN : Snowflake doit aussi calculer les valeurs NULL pour les lignes ne correspondant pas. Les changements de côté affectent considérablement la performance.
Problème : grande table des deux côtés avec un clustering faible¶
Aucune des tables sources n’est clusterisée par la clé de jointure :
CREATE DYNAMIC TABLE order_details
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT o.order_id, o.customer_id, p.product_name, o.quantity
FROM orders o
JOIN products p ON o.product_id = p.product_id;
Solution : clusterisez la table qui change moins souvent¶
Clusterisez la table de dimensions par la clé de jointure. Ensuite, la jointure bénéficie d’une meilleure localité :
ALTER TABLE products CLUSTER BY (product_id);
CREATE DYNAMIC TABLE order_details
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT o.order_id, o.customer_id, p.product_name, o.quantity
FROM orders o
JOIN products p ON o.product_id = p.product_id;
Pour OUTER JOINs :
Placez la table qui change le plus souvent sur le côté LEFT.
Essayez de réduire les changements sur le côté opposé au mot-clé OUTER.
Pour FULL OUTER JOINs, une bonne localité est essentielle des deux côtés.
Optimiser les fonctions de fenêtre¶
Snowflake recalcule les fonctions de fenêtre pour chaque clé de partition contenant des modifications. Optimisez-les de la même manière que GROUP BY.
Exigences relatives aux clés :
Toujours inclure une clause PARTITION BY. Les fonctions de fenêtre sans PARTITION BY donne lieu à un recalcul complet.
Regrouper les données sources par clés de partition.
Maintenez les modifications à moins de 5 % des partitions.
Problème : fonction de fenêtre sans clustering de partition¶
La table source n’est pas clusterisée par la clé de partition :
CREATE DYNAMIC TABLE ranked_sales
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT
region,
salesperson,
amount,
RANK() OVER (PARTITION BY region ORDER BY amount DESC) as sales_rank
FROM daily_sales;
Solution : clusterisez par la clé de partition¶
Clusterisez la table source en fonction de la clé de partition afin que la fonction de fenêtre bénéficie de la localité :
ALTER TABLE daily_sales CLUSTER BY (region);
CREATE DYNAMIC TABLE ranked_sales
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT
region,
salesperson,
amount,
RANK() OVER (PARTITION BY region ORDER BY amount DESC) as sales_rank
FROM daily_sales;
Supprimer efficacement les doublons (DISTINCT et QUALIFY)¶
DISTINCT et QUALIFY peuvent supprimer les doublons, mais ils fonctionnent différemment.
DISTINCT : Est équivalent à GROUP BY ALL. La localité affecte directement les performances ; une faible localité entraîne des actualisations lentes.
QUALIFY avec ROW_NUMBER = 1 : Snowflake optimise le modèle QUALIFY ROW_NUMBER() ... = 1 lorsqu’il se trouve dans la projection de niveau supérieur de la table dynamique. Ce modèle fonctionne systématiquement plus rapidement qu’une actualisation complète.
L’optimisation fonctionne mieux lorsque toutes les clés PARTITION BY et ORDER BY dans la clause OVER() sont conservées dans la table dynamique (incluse dans la projection de niveau supérieur).
Recommandation : utiliser QUALIFY au lieu de DISTINCT lorsque cela est possible¶
L’exemple suivant utilise DISTINCT :
CREATE DYNAMIC TABLE unique_customers
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT DISTINCT customer_id, customer_name, email
FROM customer_events;
L’exemple suivant utilise QUALIFY :
CREATE DYNAMIC TABLE unique_customers
TARGET_LAG = '1 hour'
WAREHOUSE = my_warehouse
AS
SELECT customer_id, customer_name, email, event_time
FROM customer_events
QUALIFY ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY event_time DESC) = 1;
La version QUALIFY est plus explicite sur le doublon à conserver (le plus récent) et fonctionne toujours bien.
Supprimer les opérations DISTINCT redondantes¶
Chaque opération DISTINCT consomme des ressources à chaque actualisation. Lorsque vos données sont déjà uniques ou que vous éliminez les doublons en amont, supprimez les clauses DISTINCT inutiles.
Référence des opérateurs¶
Le tableau suivant explique comment Snowflake traite chaque opérateur SQL lors de l’actualisation incrémentielle :
Opérateur |
Comment Snowflake les traite-t-elles ? |
Notes sur les performances |
|---|---|---|
SELECT |
Applique les expressions aux lignes modifiées uniquement. |
Bonnes performances. Aucune considération particulière. |
WHERE |
Évalue le prédicat sur les lignes modifiées uniquement. |
Bonnes performances. Le coût augmente de façon linéaire avec les changements. Remarque : Un opérateur WHERE très sélectif peut nécessiter que l’entrepôt de données reste actif, même lorsque le résultat ne change pas. |
FROM <table> |
Analyse les micro-partitions que Snowflake a ajoutées ou supprimées depuis la dernière actualisation. |
Le coût augmente avec le volume des partitions modifiées. Limitez les changements à environ cinq pour cent de la table source. |
UNION ALL |
Prend l’union des changements de chaque côté. |
Bonnes performances. Aucune considération particulière. |
WITH (CTEs) |
Calcule les changements pour chaque expression de table commune. |
Bonnes performances, mais évitez les définitions de table unique trop complexes. Envisagez de procéder à un fractionnement entre plusieurs tables dynamiques. |
Agrégats scalaires |
Recalcule entièrement l’agrégat lorsque l’entrée change. |
À éviter dans les tables à performances critiques. Considérez plutôt le regroupement par une constante. |
GROUP BY |
Recalcule les agrégats pour les clés de regroupement modifiées. |
Clusterisez la source en regroupant des clés. Évitez les expressions composées dans les clés. Voir Optimiser les agrégations. |
DISTINCT |
Est équivalent à GROUP BY ALL. |
Sensible à la localité. Pensez à utiliser QUALIFY à la place. Voir Supprimer efficacement les doublons (DISTINCT et QUALIFY). |
Fonctions de fenêtre |
Recalcule pour les clés de partition modifiées. |
Toujours inclure PARTITION BY. Clusterisez la source par clés de partition. Voir Optimiser les fonctions de fenêtre. |
INNER JOIN |
Les jointures changent de chaque côté avec l’autre table. |
Bonnes performances lorsqu’un côté est petit. Clusterisez le côté qui change le moins fréquemment. Voir Optimiser les jointures. |
OUTER JOIN |
Combine la jonction intérieure avec des requêtes NOT EXISTS pour le calcul NULL. |
Opérateur le plus sensible à la localité. Voir Optimiser les jointures. |
LATERAL FLATTEN |
Appliquez l’aplatissement uniquement aux lignes modifiées. |
Bonnes performances. Le coût augmente de façon linéaire avec les changements. |
QUALIFY avec classement |
Utilise un chemin optimisé pour ROW_NUMBER/RANK/DENSE_RANK … = 1. |
Hautement efficace. Placez QUALIFY au niveau de la projection de niveau supérieur de la table dynamique. |