Snowflake, BigQuery, Redshift : spécificités de chaque plateforme.
Quand l'utiliser
Activez cette compétence lorsque l'utilisateur :
Conçoit un schéma de base de données analytique.
Veut implémenter un star schema (faits + dimensions).
Pose des questions sur les SCD, la modélisation dimensionnelle.
Doit optimiser des requêtes SQL analytiques lentes.
Migre vers Snowflake, BigQuery ou Redshift.
1. Modélisation Dimensionnelle (Kimball)
1.1 Star Schema : Structure Canonique
-- TABLE DE FAITS : mesures quantitativesCREATE TABLE fact_sensor_readings (
reading_sk BIGINTIDENTITYPRIMARY KEY, -- Surrogate key
machine_sk INTNOT NULL, -- FK vers dimension
date_sk INTNOT NULL, -- FK vers dimension temps
time_sk INTNOT NULL, -- FK vers dimension heure
temperature DECIMAL(6,2),
pression DECIMAL(6,2),
vibration (,),
cycle_time ,
created_at
);
dim_machine (
machine_sk ,
machine_id () ,
machine_type (),
site (),
zone (),
install_date ,
status (),
valid_from ,
valid_to ,
is_current
);
dim_date (
date_sk ,
,
,
quarter ,
,
month_name (),
week ,
day_of_week ,
is_weekend ,
is_holiday ,
fiscal_year ,
fiscal_quarter ,
()
);
dim_time (
time_sk ,
heure ,
,
hour_minute (),
shift (),
(heure, )
);
DECIMAL
6
2
INT
TIMESTAMP
DEFAULT
CURRENT_TIMESTAMP
-- TABLE DE DIMENSION : attributs descriptifs
CREATE TABLE
INT
IDENTITY
PRIMARY KEY
VARCHAR
20
NOT NULL
VARCHAR
50
VARCHAR
100
VARCHAR
50
DATE
VARCHAR
20
DATE
NOT NULL
DATE
BOOLEAN
DEFAULT
TRUE
-- DIMENSION TEMPS (granularité jour)
CREATE TABLE
INT
PRIMARY KEY
date
DATE
NOT NULL
year
INT
INT
month
INT
VARCHAR
20
INT
INT
BOOLEAN
BOOLEAN
INT
INT
UNIQUE
date
-- DIMENSION HEURE (granularité minute)
CREATE TABLE
INT
PRIMARY KEY
INT
minute
INT
VARCHAR
5
-- HH:MM
VARCHAR
20
-- Matin/Après-midi/Nuit
UNIQUE
minute
1.2 Requêtage Star Schema
-- Analyse OEE par site et par moisSELECT
m.site,
d.year,
d.month,
COUNT(DISTINCT f.machine_sk) AS machines_actives,
AVG(f.temperature) AS temp_moyenne,
MAX(f.temperature) AS temp_max,
COUNT(*) AS nb_releves
FROM fact_sensor_readings f
JOIN dim_machine m ON f.machine_sk = m.machine_sk
JOIN dim_date d ON f.date_sk = d.date_sk
WHERE m.is_current =TRUEAND d.year =2026GROUPBY m.site, d.year, d.month
ORDERBY m.site, d.year, d.month;
2. SCD (Slowly Changing Dimensions)
2.1 Types de SCD
Type
Comportement
Usage
SCD 0
Rétroactif fixe
Colonnes qui ne changent jamais
SCD 1
Écrasement
Correction d'erreur, pas d'historique
SCD 2
Nouvelle version
Historique complet (le plus courant)
SCD 3
Colonne précédente
Besoin de l'ancienne valeur uniquement
SCD 6
Hybride 1+2+3
Tracking + current value
2.2 SCD Type 2 Implementation (SQL)
-- Mise à jour SCD Type 2MERGEINTO dim_machine AS target
USING (
SELECT machine_id, machine_type, site, zone
FROM staging_machine_updates
) AS source
ON target.machine_id = source.machine_id AND target.is_current =TRUE-- Si les données ont changé : fermer l'ancienne versionWHEN MATCHED AND (
target.machine_type <> source.machine_type OR
target.site <> source.site OR
target.zone <> source.zone
) THENUPDATESET
valid_to =CURRENT_DATE,
is_current =FALSE-- Nouvelle versionINSERT (machine_id, machine_type, site, zone, valid_from, valid_to, is_current)
VALUES (source.machine_id, source.machine_type, source.site, source.zone,
CURRENT_DATE, NULL, TRUE);
2.3 SCD Type 2 Query (Snapshot Temporel)
-- État des machines à une date donnéeSELECT f.*, m.machine_type, m.site, m.zone
FROM fact_sensor_readings f
JOIN dim_machine m ON f.machine_sk = m.machine_sk
WHERE m.valid_from <='2026-06-15'AND (m.valid_to ISNULLOR m.valid_to >'2026-06-15');
3. SQL Analytique Avancé
3.1 Fenêtrage (Window Functions)
-- Rang et comparaison temporelleSELECT
machine_id,
date,
temperature,
AVG(temperature) OVER (
PARTITIONBY machine_id
ORDERBYdateROWSBETWEEN6 PRECEDING ANDCURRENTROW
) AS moyenne_7j,
temperature -LAG(temperature, 1) OVER (
PARTITIONBY machine_id ORDERBYdate
) AS variation_jour,
RANK() OVER (
PARTITIONBY machine_id
ORDERBY temperature DESC
) AS rang_chaud
FROM sensor_readings;
-- Cumul mensuelSELECT
site,
date,
nb_releves,
SUM(nb_releves) OVER (
PARTITIONBY site, EXTRACT(YEAR_MONTH FROMdate)
ORDERBYdate
) AS cumul_mensuel
FROM daily_agg;
3.2 GROUP BY Extensions (Cubes, Rollup, Grouping Sets)
-- ROLLUP : hiérarchie (site → zone → machine)SELECT
site, zone, machine_id,
AVG(temperature) AS temp_moyenne,
GROUPING(site) AS is_site_total,
GROUPING(zone) AS is_zone_total
FROM fact_sensor_readings f
JOIN dim_machine m ON f.machine_sk = m.machine_sk
GROUPBYROLLUP(site, zone, machine_id);
-- CUBE : toutes les combinaisonsSELECT site, zone, machine_id, AVG(temperature)
FROM fact_sensor_readings f
JOIN dim_machine m ON f.machine_sk = m.machine_sk
GROUPBYCUBE(site, zone, machine_id);
-- GROUPING SETS : combinaisons spécifiquesSELECT site, zone, machine_id, AVG(temperature)
FROM fact_sensor_readings f
JOIN dim_machine m ON f.machine_sk = m.machine_sk
GROUPBYGROUPING SETS (
(site, zone),
(site),
(zone),
()
);
3.3 Pivot / Unpivot
-- PIVOT : transformer des lignes en colonnesSELECT*FROM (
SELECT machine_type, month, temperature
FROM fact_sensor_readings f
JOIN dim_machine m ON f.machine_sk = m.machine_sk
JOIN dim_date d ON f.date_sk = d.date_sk
WHERE d.year =2026
)
PIVOT (
AVG(temperature)
FORmonthIN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
) AS p;
-- UNPIVOT (BigQuery) : colonnes → lignesSELECT machine_id, month, avg_temp
FROM `project.dataset.kpi_table`
UNPIVOT (
avg_temp FORmonthIN (jan, feb, mar, apr)
);
4. Data Vault 2.0
4.1 Structure Data Vault
-- HUB : clés d'entreprise (business keys)CREATE TABLE hub_machine (
machine_hk CHAR(32) PRIMARY KEY, -- Hash MD5 de la business key
machine_id VARCHAR(20) NOT NULL,
load_date TIMESTAMP,
record_source VARCHAR(100),
UNIQUE(machine_id)
);
-- LINK : associations entre hubsCREATE TABLE link_sensor_machine (
sensor_machine_lk CHAR(32) PRIMARY KEY,
sensor_hk CHAR(32) REFERENCES hub_sensor(sensor_hk),
machine_hk CHAR(32) REFERENCES hub_machine(machine_hk),
load_date TIMESTAMP,
record_source VARCHAR(100)
);
-- SATELLITE : attributs contextuelsCREATE TABLE sat_machine_details (
machine_hk CHAR(32) REFERENCES hub_machine(machine_hk),
load_date TIMESTAMP,
record_source VARCHAR(100),
machine_type VARCHAR(50),
site VARCHAR(100),
zone VARCHAR(50),
install_date DATE,
hash_diff CHAR(32), -- Hash de tous les attributs pour détecter les changementsPRIMARY KEY (machine_hk, load_date)
);
4.2 Data Vault vs Kimball
Critère
Kimball (Star Schema)
Data Vault 2.0
Complexité
Faible (compréhension métier)
Élevée (technique)
Audit trail
SCD type 2 limité
Complet (chaque changement)
Intégration multi-source
Difficile
Naturelle
Performance requêtes
Excellente (star)
Nécessite une couche de présentation
Cas d'usage
BI, tableaux de bord
Data Lakehouse, audit, conformité
5. Spécificités des Plateformes Cloud
5.1 Snowflake
-- Clustering automatiqueALTER TABLE fact_sensor_readings
CLUSTER BY (date_sk, machine_sk);
-- Materialized viewCREATE MATERIALIZED VIEW mv_machine_daily ASSELECT date_sk, machine_sk, AVG(temperature) AS avg_temp
FROM fact_sensor_readings
GROUPBY date_sk, machine_sk;
-- Time Travel (accès aux données historiques)SELECT*FROM fact_sensor_readings
AT (TIMESTAMP=>'2026-07-20 10:00:00'::TIMESTAMP);
-- Zero-copy cloning (environnement de test)CREATE DATABASE dw_dev CLONE dw_prod;
-- Query profilingSELECT*FROMTABLE(
INFORMATION_SCHEMA.QUERY_HISTORY_BY_SESSION(
SESSION_ID =><session_id>,
RESULT_LIMIT =>100
)
);
5.2 BigQuery
-- Partitionnement et clusteringCREATE TABLE `project.dw.fact_sensor_readings`
PARTITIONBYDATE(timestamp)
CLUSTER BY machine_sk
OPTIONS(
require_partition_filter =TRUE,
partition_expiration_days =365
);
-- BI Engine (accélération en mémoire)-- Réserver 10 Go pour les tables les plus interrogées-- Scripting et procéduresDECLARE target_date DATEDEFAULTCURRENT_DATE();
CREATE TEMP TABLE temp_agg ASSELECT machine_sk, COUNT(*) AS cnt
FROM fact_sensor_readings
WHEREDATE(timestamp) = target_date;
-- Slot estimation (optimisation des coûts)SELECT
query,
total_slot_ms,
total_bytes_billed
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL1HOUR);
5.3 Amazon Redshift
-- Distribution style (clairé par machine jointe)CREATE TABLE fact_sensor_readings (
...
) DISTKEY(machine_sk)
SORTKEY(date_sk, time_sk);
-- Compression
ANALYZE COMPRESSION fact_sensor_readings;
-- Materialized viewsCREATE MATERIALIZED VIEW mv_daily_avg ASSELECT date_sk, machine_sk, AVG(temperature) AS avg_temp
FROM fact_sensor_readings
GROUPBY date_sk, machine_sk;
-- Query plan
EXPLAIN
SELECT m.site, AVG(f.temperature)
FROM fact_sensor_readings f
JOIN dim_machine m ON f.machine_sk = m.machine_sk
GROUPBY m.site;
-- WLM (Workload Management) — queues-- Configurer les queues pour séparer ETL et BI
6. Optimisation des Performances
6.1 Stratégies par Plateforme
Technique
Snowflake
BigQuery
Redshift
Partitionnement
CLUSTER BY
PARTITION BY
SORTKEY
Distribution
Automatique
Automatique
DISTKEY
Compression
Automatique
Automatique
ENCODE manuel
Cache
Result set cache
BI Engine
Result cache
Tuning slots
Virtual warehouse
Slots réservés
WLM queues
6.2 Analyse de Requêtes Lentes
-- Identifier les goulots d'étranglement-- 1. Full table scans
EXPLAIN SELECT ...; -- Vérifier l'utilisation des indexes/clés-- 2. Jointures distribuées (Redshift)-- Éviter les broadcasts de grandes tables-- 3. Trop de partitions luesSELECT table_name, SUM(row_count) ASrowsFROM fact_sensor_readings
WHERE date_sk BETWEEN20250101AND20250722;
--> Si millions de lignes : partition filter manquant-- 4. Compression inefficace
ANALYZE COMPRESSION dim_machine;
Pièges Courants (Pitfalls)
Trop de colonnes dans la table de faits.
Erreur : Mettre des attributs dimensionnels dans la table de faits → jointures impossibles, redondance.
Correction : Les attributs descriptifs vont dans les dimensions, les mesures dans les faits.
SCD Type 2 sans clé de substitution (surrogate key).
Erreur : Utiliser la clé naturelle (machine_id) comme clé primaire → impossible d'avoir plusieurs versions.
Correction : Toujours créer une machine_sk auto-incrémentée.
Jointure sans index/clé de distribution.
Erreur : Faire JOIN sur une colonne non indexée → full scan des deux tables.
Correction : Vérifier les clés de jointure, indices, DISTKEY (Redshift), clustering.
Requêtes sans partition pruning.
Erreur : WHERE sans filtre sur la colonne de partition → toutes les partitions lues.
Correction : Toujours filtrer sur la colonne de partition (date_sk, date, timestamp).
Dimension date générée manuellement (incomplète).
Erreur : Pas de table dim_date → pas de capacité d'analyse calendaire, jours fériés, etc.
Correction : Générer la dim_date sur 10+ ans avec tous les attributs calendaires.
Liste de Vérification (Checklist)
Star schema : faits + dimensions clairement séparés.
Surrogate key (auto-incrément) sur chaque dimension.
SCD Type 2 pour les dimensions qui changent dans le temps.
Table dim_date générée (10 ans, jours fériés, trimestres fiscaux).
Partitionnement/clustering sur les colonnes de filtrage.
Compression activée sur les tables de faits.
Tests de performance (EXPLAIN, profiling).
Data Vault ou Kimball selon les besoins d'audit.
Materialized views pour les agrégations fréquentes.
Documentation du modèle dimensionnel (dictionnaire de données).