Di seguito la risposta specifica di BigQuery!
BigQuery funziona meglio quando i tuoi dati sono denormalizzati. Piuttosto che preservare uno schema relazionale come uno schema a stella o a fiocco di neve, è possibile migliorare le prestazioni denormalizzando i dati e sfruttando i campi annidati e ripetuti. I campi annidati e ripetuti possono mantenere le relazioni senza l’impatto sulle prestazioni del mantenimento di uno schema relazionale (normalizzato).
I risparmi di storage dai dati normalizzati sono meno preoccupanti nei sistemi moderni. L’aumento dei costi di archiviazione vale i guadagni di prestazioni derivanti dalla denormalizzazione dei dati. Le giunzioni richiedono il coordinamento dei dati (larghezza di banda di comunicazione). La denormalizzazione localizza i dati nei singoli slot in modo che l’esecuzione possa essere fatta in parallelo.
Se avete bisogno di mantenere le relazioni mentre denormalizzate i vostri dati, usate campi annidati e ripetuti invece di appiattire completamente i vostri dati. Quando i dati relazionali sono completamente appiattiti, la comunicazione di rete (shuffling) può avere un impatto negativo sulle prestazioni della query.
Per esempio, denormalizzare uno schema di ordini senza usare campi annidati e ripetuti può richiedere di raggruppare per un campo come order_id (quando c’è una relazione uno-a-molti). A causa del rimescolamento coinvolto, raggruppare i dati è meno performante che denormalizzare i dati usando campi annidati e ripetuti.
Nota: In alcune circostanze, denormalizzare i dati e usare campi annidati e ripetuti potrebbe non portare ad un aumento delle prestazioni.
Si può vedere di più nella sezione Denormalizzare i dati quando possibile dei documenti di BigQuery
Finalmente: BigQuery non richiede una denormalizzazione completamente piatta. Puoi usare campi annidati e ripetuti per mantenere le relazioni.
Di seguito un esempio di produzione di una tabella denormalizzata dalle tre tabelle iniziali normalizzate nella tua domanda
#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)
questo produrrà una tabella con lo schema seguente
Ovviamente, questo è uno schema più incentrato sul cliente. A seconda delle vostre esigenze potete allo stesso modo creare uno schema incentrato sul prodotto. O in realtà entrambi e usare quello appropriato in base al caso d’uso
Puoi fare dei test, giocare con quanto sopra usando dati fittizi come nell’esempio sottostante
#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)
con output