Vous trouverez ci-dessous une réponse spécifique à BigQuery !
BigQuery est plus performant lorsque vos données sont dénormalisées. Plutôt que de préserver un schéma relationnel tel qu’un schéma en étoile ou en flocon de neige, vous pouvez améliorer les performances en dénormalisant vos données et en tirant parti des champs imbriqués et répétés. Les champs imbriqués et répétés peuvent maintenir les relations sans l’impact sur les performances de la préservation d’un schéma relationnel (normalisé).
Les économies de stockage liées aux données normalisées sont moins préoccupantes dans les systèmes modernes. Les augmentations des coûts de stockage valent les gains de performance liés à la dénormalisation des données. Les jointures nécessitent une coordination des données (bande passante de communication). La dénormalisation localise les données dans des slots individuels afin que l’exécution puisse se faire en parallèle.
Si vous devez maintenir des relations tout en dénormalisant vos données, utilisez des champs imbriqués et répétés au lieu d’aplatir complètement vos données. Lorsque les données relationnelles sont complètement aplaties, la communication réseau (shuffling) peut avoir un impact négatif sur les performances des requêtes.
Par exemple, la dénormalisation d’un schéma de commandes sans utiliser de champs imbriqués et répétés peut vous obliger à regrouper par un champ tel que order_id (lorsqu’il existe une relation un à plusieurs). En raison du brassage impliqué, le regroupement des données est moins performant que la dénormalisation des données à l’aide de champs imbriqués et répétés.
Note : dans certaines circonstances, la dénormalisation de vos données et l’utilisation de champs imbriqués et répétés peuvent ne pas entraîner une augmentation des performances.
Vous pouvez en voir plus dans la section Dénormaliser les données chaque fois que possible des docs BigQuery
Finalement : BigQuery n’exige pas une dénormalisation complètement plate. Vous pouvez utiliser des champs imbriqués et répétés pour maintenir les relations.
Vous trouverez ci-dessous un exemple de production d’une table dénormalisée à partir de trois tables normalisées initiales dans votre question
#standardSQLSELECT ANY_VALUE(c).*, ARRAY_AGG((SELECT AS STRUCT p.*, s.product_storage_building)) productsFROM `project.dataset.customers` cLEFT JOIN `project.dataset.storage` s USING (customer_id)LEFT JOIN `project.dataset.products` p USING (product_id)GROUP BY FORMAT('%t', c)
Ceci produira une table avec le schéma ci-dessous
Evidemment, ce schéma est plus axé sur le client. Selon vos besoins, vous pouvez de la même manière créer un schéma centré sur le produit. Ou en fait les deux et utiliser le approprié en fonction du cas d’utilisation
Vous pouvez tester, jouer avec ce qui précède en utilisant des données factices comme dans l’exemple ci-dessous
#standardSQLWITH `project.dataset.customers` AS ( SELECT 1 customer_id, 'country 1' country, 'city 1' city, 'street 1' street, 1 house_number UNION ALL SELECT 2, 'country 1', 'city 2', 'street 2', 2 UNION ALL SELECT 3, 'country 1', 'city 3', 'street 3', 3 UNION ALL SELECT 4, 'country 2', 'city 4', 'street 4', 4 UNION ALL SELECT 5, 'country 2', 'city 5', 'street 5', 5 ), `project.dataset.products` AS ( SELECT 1 product_id, 'product 1' product_name, 'color 1' product_color, 'origin 1' product_origin UNION ALL SELECT 2, 'product 2', 'color 2', 'origin 2' UNION ALL SELECT 3, 'product 3', 'color 3', 'origin 3' UNION ALL SELECT 4, 'product 4', 'color 4', 'origin 4' ), `project.dataset.storage` AS ( SELECT 1 product_id, 1 customer_id, 'building 1' product_storage_building UNION ALL SELECT 2, 1, 'building 1' UNION ALL SELECT 3, 1, 'building 1' UNION ALL SELECT 2, 2, 'building 2' UNION ALL SELECT 3, 2, 'building 3' UNION ALL SELECT 4, 2, 'building 3' UNION ALL SELECT 1, 3, 'building 1' UNION ALL SELECT 3, 3, 'building 1' )SELECT ANY_VALUE(c).*, ARRAY_AGG((SELECT AS STRUCT p.*, s.product_storage_building)) productsFROM `project.dataset.customers` cLEFT JOIN `project.dataset.storage` s USING (customer_id)LEFT JOIN `project.dataset.products` p USING (product_id)GROUP BY FORMAT('%t', c)
avec sortie
.