ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Jointures Lightdash et protection contre le fanout

Comment définir des jointures entre des modèles dbt dans Lightdash YAML, pourquoi la propriété relationship est déterminante pour la précision des métriques, et comment Lightdash signale le risque de fanout dans les jointures one-to-many.

Planté
dbtanalyticsdata modeling

Les jointures dans Lightdash permettent aux utilisateurs de combiner des dimensions et des métriques provenant de plusieurs modèles dbt dans une seule requête Explore. Sans jointures, chaque modèle est une île isolée — les utilisateurs ne peuvent analyser que les dimensions et métriques qui résident sur le même modèle. Avec des jointures, un modèle d’ordres peut intégrer des attributs clients depuis un modèle CRM, des données de campagne depuis un modèle marketing, ou des détails produits depuis un modèle catalogue, le tout dans une seule requête sans que personne n’écrive du SQL.

Définir une jointure

Les jointures se placent sous meta.joins au niveau du modèle :

models:
- name: mrt__sales__orders
meta:
primary_key: order__id
joins:
- join: mrt__crm__customers
sql_on: >
${mrt__sales__orders.customer__id}
= ${mrt__crm__customers.customer__id}
relationship: many-to-one
type: left

La clause sql_on utilise la syntaxe de référence de dimension de Lightdash : ${model_name.column_name}. Il s’agit d’un template Jinja-like qui est compilé en condition de jointure SQL réelle. L’utilisation de références de dimension plutôt que de noms de colonnes bruts signifie que la jointure respecte tout alias de colonne ou surcharge de schéma que vous avez configuré.

Le type est left par défaut si omis. Les quatre options sont inner, left, right et full. Les jointures left sont le bon choix par défaut pour la plupart des cas d’usage BI — vous souhaitez toutes les lignes du modèle principal, avec des nulls là où le modèle joint n’a pas de correspondance, plutôt que de supprimer silencieusement les lignes non correspondantes.

La propriété relationship et son utilité

La propriété relationship n’est pas cosmétique. Lightdash l’utilise pour déterminer quelles métriques du modèle joint sont sûres à utiliser.

Les options sont many-to-one, one-to-one et one-to-many. Une mauvaise configuration est l’une des sources les plus courantes de métriques gonflées dans les outils BI.

Voici le problème : dans une jointure one-to-many, chaque ligne du modèle principal correspond à plusieurs lignes du modèle joint. Cela provoque une duplication de lignes côté modèle principal. Toute métrique qui somme ou compte des lignes du modèle principal sera gonflée par le facteur de multiplication.

Prenons un modèle d’ordres joint à un modèle de line_items (un ordre, plusieurs lignes). Si vous calculez total_revenue (une somme sur le modèle d’ordres) via cette jointure, chaque ligne d’ordre est comptée une fois pour chaque ligne qu’elle contient. Un ordre avec cinq lignes contribue cinq fois à la somme. Le résultat est faux.

Lightdash utilise la propriété relationship pour signaler ce risque. Dans une jointure one-to-many :

  • Signalées comme risquées : les métriques sum, average, count du modèle principal
  • Sûres à utiliser : min, max, count_distinct du modèle principal

Lightdash avertit les utilisateurs avant d’exécuter une requête combinant une métrique signalée avec une dimension jointe en one-to-many. L’avertissement ne bloque pas la requête — les utilisateurs peuvent continuer — mais il rend le risque visible au moment de l’analyse plutôt qu’après.

joins:
- join: mrt__sales__line_items
sql_on: >
${mrt__sales__orders.order__id}
= ${mrt__sales__line_items.order__id}
relationship: one-to-many # triggers fanout warnings on sum/count metrics
type: left

La bonne correction pour ce pattern réside généralement dans les modèles dbt eux-mêmes : si vous avez besoin de métriques au niveau ordre et de dimensions de lignes ensemble, construisez un mart qui les pré-join à la bonne granularité plutôt que de vous appuyer sur une jointure à l’exécution. Mais lorsqu’une jointure à l’exécution est véritablement nécessaire, la propriété relationship rend au moins le risque visible.

Propriétés de jointure supplémentaires

fields

Autorise une liste spécifique de dimensions ou métriques depuis le modèle joint. Par défaut, tous les champs non masqués du modèle joint apparaissent dans la barre latérale Explore. fields restreint cela à ce qui est utile :

joins:
- join: mrt__crm__customers
sql_on: >
${mrt__sales__orders.customer__id}
= ${mrt__crm__customers.customer__id}
relationship: many-to-one
type: left
fields:
- customer__name
- customer__segment
- customer__country

C’est particulièrement utile pour les grands modèles. Si votre modèle clients a 40 colonnes mais que vous n’en avez besoin que de 3 dans le contexte de l’Explore des ordres, exposer les 40 crée une barre latérale encombrée et expose des colonnes qui peuvent ne pas avoir de sens quand elles sont consultées via le prisme des ordres.

hidden

hidden: true joint le modèle sans l’exposer dans la barre latérale. La jointure s’exécute quand même — les colonnes du modèle joint deviennent disponibles pour le filtrage — mais les utilisateurs ne peuvent pas voir ni sélectionner ses dimensions comme champs explicites :

joins:
- join: mrt__access__user_permissions
sql_on: >
${mrt__sales__orders.customer__id}
= ${mrt__access__user_permissions.user__id}
relationship: many-to-one
type: inner
hidden: true

Le cas d’usage ici est le filtrage au niveau ligne. Une jointure masquée vers un modèle de permissions peut garantir que les utilisateurs ne voient que les données auxquelles ils sont autorisés, sans exposer le modèle de permissions comme une entité navigable dans la vue Explore.

alias

Renomme le modèle joint quand le même modèle doit apparaître deux fois :

joins:
- join: mrt__crm__contacts
alias: billing_contact
sql_on: >
${mrt__sales__orders.billing_contact__id}
= ${billing_contact.contact__id}
relationship: many-to-one
type: left
- join: mrt__crm__contacts
alias: shipping_contact
sql_on: >
${mrt__sales__orders.shipping_contact__id}
= ${shipping_contact.contact__id}
relationship: many-to-one
type: left

Sans alias, vous ne pouvez pas joindre le même modèle deux fois — la seconde jointure n’aurait aucun moyen de se distinguer de la première. Avec les alias, les deux jointures utilisent des noms différents, et leurs champs apparaissent comme des sections séparées dans la barre latérale (billing_contact.* et shipping_contact.*).

Quand utiliser les jointures vs. les marts plus larges

La tension dans la conception BI : faut-il tout pré-joindre dans un mart large, ou garder des modèles étroits et utiliser des jointures au niveau BI ?

Les marts pré-joints sont plus performants (la jointure s’exécute une fois au moment de la transformation, pas à chaque requête), et il n’y a pas de risque de fanout à gérer. Ce sont le bon choix quand une jointure est fréquente, la cardinalité est stable, et la granularité combinée a du sens sémantiquement comme entité unique.

Les jointures au niveau BI sont meilleures pour l’exploration ad-hoc — quand vous avez occasionnellement besoin de combiner deux modèles qui ne vont pas toujours ensemble, ou quand le produit croisé de combinaisons nécessiterait trop de marts pré-construits. Les avertissements de fanout de Lightdash rendent les jointures ad-hoc plus sûres que dans un outil sans conscience des relations.

La heuristique pratique : si les analystes joignent constamment les modèles A et B dans la vue Explore, c’est un signal pour pré-construire cette jointure dans dbt. S’ils joignent A et B occasionnellement, pour des analyses spécifiques, la jointure Explore est le bon choix. Réservez la couche mart aux combinaisons stables et fréquemment utilisées ; laissez les jointures Lightdash gérer les cas d’usage exploratoires ponctuels.