Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

📈 Amazon Redshift – DWH, Spectrum & VACUUM

Guide complet IDEO-Lab sur le Data Warehouse (MPP) d'AWS, incluant Spectrum (S3).

1.1

Concept : Data Warehouse (DWH)

AWS, SQL Analytique (OLAP), MPP (ParallĂšle).

Redshift DWH AWS
1.2

Architecture : MPP

Massively Parallel Processing. Leader & Compute Nodes.

MPP Leader Node Compute Node
1.3

vs. Snowflake / BigQuery

Provisionné (Redshift) vs SaaS (Snowflake/BQ).

Snowflake BigQuery
2.1

NƓud : Leader Node

Le "Cerveau". (Coordinateur, Query Planner, Optimizer).

Leader Node Optimizer
2.2

NƓud : Compute Node & Slices

Le "Muscle". (Stockage, Exécution). Slices (vCPUs).

Compute Node Slices
2.3

Types de NƓuds (DC2 vs RA3)

DC2 (Stockage Couplé) vs RA3 (Stockage Séparé S3).

DC2 RA3 Séparation
3.1

Stockage : Colonnaire

Stockage par colonnes (optimisé SELECT, AVG).

Colonnaire OLAP
3.2

Distribution Keys (DISTKEY)

Comment les données sont "distribuées" (KEY, ALL, EVEN).

DISTKEY Distribution
3.3

Sort Keys (SORTKEY)

Comment les données sont "triées" (COMPOUND, INTERLEAVED).

SORTKEY Tri
4.1

Concept : Redshift Spectrum

RequĂȘter (SELECT) des donnĂ©es directement sur S3 (Data Lake).

Spectrum S3 Data Lake
4.2

Spectrum : External Tables

CREATE EXTERNAL TABLE, Glue Data Catalog.

External Table Glue
4.3

Spectrum : Cas d'Usage

Data Lake (Froid) vs DWH (Chaud). (JOIN S3 + Local).

Lakehouse Froid vs Chaud
5.1

Ingestion : Commande COPY

Chargement "Bulk" (massif) depuis S3 (Parquet, CSV).

COPY Ingestion S3
5.2

Gestion : WLM

Workload Management. Files (Queues) de priorités.

WLM QoS
5.3

Gestion : Concurrency Scaling

Auto-scale (Spin-up) de clusters (éphémÚres) pour les pics.

Concurrency Scaling Auto-scale
6.1

Maintenance : VACUUM

(Crucial) RécupÚre l'espace (DELETE), Re-trie (SORTKEY).

VACUUM DELETE SORT
6.2

Maintenance : ANALYZE

Met Ă  jour les statistiques (Stats) pour l'Optimizer (Leader).

ANALYZE Statistiques
6.3

Admin Cheat-sheet

Commandes (COPY, VACUUM, ANALYZE).

Cheatsheet Admin
1.1 Concept : Data Warehouse (DWH) MPP
Qu'est-ce qu'Amazon Redshift ?

Amazon Redshift (basé sur PostgreSQL 8.0) est un Data Warehouse (EntrepÎt de Données) "entiÚrement managé" (PaaS) sur AWS. C'est un DWH "historique" du Cloud, conçu pour l'analytique SQL (OLAP) et la Business Intelligence (BI).

Objectif : ExĂ©cuter des requĂȘtes SQL complexes (JOIN, GROUP BY, Window Functions) trĂšs rapidement sur des volumes massifs (PĂ©taoctets) de donnĂ©es.

Architecture : MPP (Massively Parallel Processing)

Redshift (comme Teradata ou Netezza) est un DWH MPP (Traitement ParallĂšle Massif). Une requĂȘte n'est pas exĂ©cutĂ©e par 1 serveur, mais distribuĂ©e (parallĂ©lisĂ©e) sur des centaines de CPU (Slices) qui travaillent en mĂȘme temps.

1.2 Architecture : MPP (Leader & Compute Nodes)

Un "Cluster" Redshift est composĂ© de deux types de NƓuds (Instances EC2) :

(Client SQL / BI Tool)
       │
       │ (Connexion SQL, Port 5439)
       ▌
[ 1. LEADER NODE ] (1 NƓud)
   (Le "Cerveau" : Optimizer, Query Planner)
   (Ne stocke pas de données)
   │
   │ (Distribue le plan d'exĂ©cution
   │  parallùle aux NƓuds Compute)
   │
   ├────────â–ș [ 2. COMPUTE NODE 1 ] (Le "Muscle")
   │            ├─ [Slice 0 (vCPU)] -> (Stocke/Scanne 1/N)
   │            └─ [Slice 1 (vCPU)] -> (Stocke/Scanne 1/N)
   │
   ├────────â–ș [ 2. COMPUTE NODE 2 ] (Le "Muscle")
   │            ├─ [Slice 2 (vCPU)] -> (Stocke/Scanne 1/N)
   │            └─ [Slice 3 (vCPU)] -> (Stocke/Scanne 1/N)
   │
   ...
   │
   └────────â–ș [ 2. COMPUTE NODE 'N' ]
  • Leader Node (NƓud Principal) : (1 par cluster) Le "cerveau" (Control Plane). Reçoit la requĂȘte SQL, la parse, l'optimise (plan d'exĂ©cution), la compile en C++, et coordonne l'exĂ©cution sur les NƓuds Compute.
  • Compute Nodes (NƓuds de Calcul) : (1 Ă  128 nƓuds) Les "muscles" (Data Plane). Ils stockent les donnĂ©es (distribuĂ©es) et exĂ©cutent les tĂąches (scan, join, aggregate) en parallĂšle.
  • Slices (Tranches) : Chaque NƓud Compute est divisĂ© en "Slices". (1 Slice = 1 vCPU/RAM). C'est l'unitĂ© de parallĂ©lisme.
1.3 Comparaison : Redshift vs. Snowflake vs. BigQuery
CritĂšreRedshift (AWS)Snowflake (SaaS)BigQuery (GCP)
ArchitectureProvisionné (Cluster) (DC2/RA3).SaaS (Séparé) (Stockage vs Compute).Serverless (SaaS) (Dremel).
ModÚle ComputeCluster (Taille Fixe). (Payé 24/7).Virtual Warehouses (Taille variable, Auto-Suspend).On-Demand (Slots partagés) ou Reservations (Slots dédiés).
Tarification (Compute)$/Heure (Cluster ON).$/Seconde (Warehouse RUNNING).$/To Scanné (On-Demand).
Admin (DBA)Lourd (Requis). (VACUUM, ANALYZE, DISTKEY, SORTKEY).Zéro Admin (Automatisé).Zéro Admin (Automatisé).
ÉcosystĂšmeAWS (Natif, trĂšs intĂ©grĂ©).Multi-Cloud (AWS, Azure, GCP).GCP (Natif).
Point FortIntégration AWS, Coût (si charge 24/7).Facilité (Zéro Admin), Data Sharing, Isolation (Compute).Scalabilité (Serverless), BQML (IA).
2.1 NƓud : Leader Node (Le Cerveau)

Le Leader Node (NƓud Principal) est le point d'entrĂ©e (Endpoint) et le "cerveau" (Optimizer) du cluster. Il ne participe pas au scan des donnĂ©es.

RĂŽles du Leader Node
  1. Endpoint (SQL) : Reçoit la connexion SQL (ex: psql, Tableau) sur le port (ex: 5439).
  2. Parser/Optimizer (Analyseur) : Parse le SQL, vérifie les permissions, et consulte les statistiques (voir 6.2) pour créer le Plan d'Exécution (Query Plan) le plus efficace (ex: "Quel JOIN en premier ?").
  3. Compiler (Compilateur) : (Optimisation) Compile le Plan (SQL) en code C++ (binaire) optimisé.
  4. Coordinator (Coordinateur) : Distribue (dispatch) les étapes (segments) du plan compilé aux Compute Nodes (2.2).
  5. Aggregator (Agrégateur) : Reçoit les résultats partiels des Compute Nodes, les agrÚge (ex: SUM final), et renvoie le résultat final au client.
2.2 NƓud : Compute Node & Slices (Le Muscle)

Les Compute Nodes (NƓuds de Calcul) sont les "workers" (muscles) qui stockent les donnĂ©es et exĂ©cutent les requĂȘtes.

Slices (Tranches)

Chaque Compute Node est divisé en Slices. Une Slice est l'unité de parallélisme (elle possÚde sa propre portion de RAM/Disque et 1 vCPU).

Exemple : Un cluster dc2.large (2 NƓuds). Chaque nƓud dc2.large a 2 Slices.
Total = 4 Slices (4 vCPUs).

Lorsqu'une table est créée, Redshift distribue (DISTKEY) les données entre les Slices.

(Table 'Ventes', 1M Lignes)
   │
   ├─â–ș [Slice 0] (Stocke 250k Lignes) -> (ExĂ©cute 1/4 du 'WHERE')
   ├─â–ș [Slice 1] (Stocke 250k Lignes) -> (ExĂ©cute 1/4 du 'WHERE')
   ├─â–ș [Slice 2] (Stocke 250k Lignes) -> (ExĂ©cute 1/4 du 'WHERE')
   └─â–ș [Slice 3] (Stocke 250k Lignes) -> (ExĂ©cute 1/4 du 'WHERE')

RĂ©sultat (MPP) : La requĂȘte (SELECT) s'exĂ©cute 4x plus vite (en parallĂšle).

2.3 Types de NƓuds (DC2 vs RA3)

Le choix du type de NƓud (Compute) dĂ©finit l'architecture de stockage.

Type : DC2 (Dense Compute)

(Ancien) C'est l'architecture "classique" (Shared-Nothing / Couplée).

Stockage : Stockage local (SSD). Les données sont stockées sur les disques SSD du Compute Node.

ProblĂšme (Couplage) :

  • Si vous manquez de Stockage (Disque), vous devez ajouter des NƓuds... ce qui augmente aussi le Calcul (CPU) (et le CoĂ»t).
  • Si vous manquez de Calcul (CPU), vous devez ajouter des NƓuds... ce qui augmente aussi le Stockage (et le CoĂ»t).

Type : RA3 (Séparation Stockage/Compute)

(Moderne, "Aqua") C'est la réponse de Redshift à Snowflake (1.2).

Architecture (Séparée) :

  1. Stockage (Managed Storage) : Les données (Micro-Partitions) sont stockées sur S3 (géré par Redshift).
  2. Compute (NƓuds RA3) : Les nƓuds RA3 agissent comme un Cache (SSD) intelligent + Compute (CPU/RAM).

Avantage : Permet de scaler le Stockage (S3, illimité) et le Calcul (Taille du cluster RA3) indépendamment.

3.1 Stockage : Colonnaire

Redshift (comme tous les DWH analytiques) utilise un stockage colonnaire.

Ligne (OLTP) vs Colonne (OLAP)
Stockage "Ligne" (Row-based) (MySQL, Postgres)

Optimisé pour INSERT/UPDATE.

(Ligne 1) [ID_A | Nom_A | Ville_A]
(Ligne 2) [ID_B | Nom_B | Ville_B]
(Ligne 3) [ID_C | Nom_C | Ville_C]

ProblĂšme (RequĂȘte) : SELECT AVG(Age) doit lire tout le bloc (ID, Nom, Ville, Age) pour chaque ligne (lent).

Stockage "Colonne" (Columnar) (Redshift)

Optimisé pour SELECT (OLAP).

(Fichier Col_ID)   [ID_A | ID_B | ID_C]
(Fichier Col_Nom)  [Nom_A | Nom_B | Nom_C]
(Fichier Col_Ville) [Ville_A | Ville_B | Ville_C]
(Fichier Col_Age)  [Age_A | Age_B | Age_C]

Solution : SELECT AVG(Age) ne lit que le fichier "Col_Age" (trĂšs rapide) et ignore les autres (Nom, Ville...).

Compression : Les donnĂ©es d'une mĂȘme colonne se ressemblent -> TrĂšs haute compression (ex: ZSTD, LZO).

3.2 Clés de Distribution (DISTKEY)

La Clé de Distribution (DISTKEY) est le choix d'optimisation (admin) le plus important. Elle définit comment Redshift "distribue" (répartit) les lignes d'une table sur les Slices (2.2).

Style (DISTSTYLE)DescriptionUsage
AUTO(Défaut) Redshift choisit (basé sur la taille). (Souvent ALL si petit, EVEN si grand).(Usage général)
EVEN(Round Robin) Distribue les lignes "tourniquet" (1-2-3-1-2-3).Tables sans JOIN, ou si pas de clé évidente.
KEY(Hash) Distribue basé sur le hash d'une colonne (DISTKEY col). (Toutes les valeurs FR sur Slice 1, US sur Slice 2...).(Tables de Faits/Dimensions) Mettre la clé de JOIN (ex: user_id) comme DISTKEY sur les 2 tables (users et ventes).
ALLDupliquer. Met une copie complĂšte de la table sur chaque Compute Node.Petites tables de Dimensions (ex: dim_pays) qui sont JOIN souvent.
Optimisation (DISTKEY=KEY)

Si users et ventes sont DISTKEY(user_id), les lignes (ex: "Bob" et "ses Ventes") sont colocalisĂ©es (sur le mĂȘme Slice). Le JOIN se fait localement (sur le Slice), sans aucun "shuffle" (mĂ©lange) rĂ©seau (trĂšs rapide).

3.3 Clés de Tri (SORTKEY)

La Clé de Tri (SORTKEY) définit comment les données sont triées (ordonnées) physiquement sur le disque (à l'intérieur d'un Slice).

Objectif : (Similaire au "Pruning" (3.2) de Snowflake) Permettre Ă  Redshift de "sauter" (ignorer) des blocs de disque entiers.

Usage : Mettre la colonne la plus filtrée (WHERE) (souvent la Date) comme SORTKEY.

Exemple (SORTKEY(date))

Si la table est triée par date, les données sont stockées comme ça :

[Bloc 1 (Janv)] [Bloc 2 (Fév)] [Bloc 3 (Mars)] ... [Bloc 12 (Déc)]

RequĂȘte : SELECT ... WHERE date = 'Mars'

Résultat : Redshift (grùce au SORTKEY) ne lit que le Bloc 3 (rapide), et ignore (saute) les 11 autres blocs (I/O réduit).

4.1 Concept : Redshift Spectrum (Query-in-Place)

Redshift Spectrum est une fonctionnalitĂ© de Redshift qui permet d'exĂ©cuter des requĂȘtes SQL directement sur des fichiers stockĂ©s dans votre Data Lake (Amazon S3).

Le ProblÚme (Données Froides)

Stocker 10 PĂ©taoctets de logs (donnĂ©es "froides", rarement requĂȘtĂ©es) dans un Cluster Redshift (Stockage local DC2) coĂ»te extrĂȘmement cher (coĂ»t des nƓuds 24/7).

La Solution (Spectrum)

Vous stockez les 10 Po de logs (froid) sur S3 (trÚs bon marché), et vous ne gardez que 1 To (chaud) dans Redshift (local).

Spectrum vous permet de requĂȘter (SELECT) les donnĂ©es sur S3 sans avoir Ă  les charger (COPY) d'abord dans Redshift.

RequĂȘte "Lakehouse" :
SELECT ...
FROM [Table Locale (Chaude)] AS T1
JOIN [Table Externe (Spectrum/S3)] AS T2
ON T1.id = T2.id

Facturation : Vous payez (comme BigQuery) au To scanné (lu) sur S3 par Spectrum.

4.2 Spectrum : Tables Externes

Pour utiliser Spectrum, vous devez créer (dans Redshift) une Table Externe (EXTERNAL TABLE) qui "pointe" vers les données (fichiers) sur S3.

Le "Metastore" (AWS Glue)

Redshift (Spectrum) a besoin d'un "catalogue" (Metastore) pour savoir oĂč sont les fichiers S3 et quel est leur schĂ©ma (colonnes).

Il utilise (généralement) le AWS Glue Data Catalog (le "Metastore" partagé d'AWS, aussi utilisé par Athena, EMR, Databricks).

-- 1. (Optionnel) Créer un "Schéma Externe"
--    lié au Catalogue Glue
CREATE EXTERNAL SCHEMA schema_s3
FROM DATA CATALOG
DATABASE 'ma_db_glue'
IAM_ROLE 'arn:aws:iam::...'
-- 2. Créer la Table Externe (pointant vers GCS)
-- (Note : La définition de la table est dans Glue,
--  Redshift ne fait que la "lire")
CREATE EXTERNAL TABLE schema_s3.logs_externes (
  id INT,
  message VARCHAR(255),
  date DATE
)
PARTITIONED BY (date) -- (Optimisation : Partitions S3)
ROW FORMAT SERDE ...
STORED AS PARQUET
LOCATION 's3://mon-bucket/logs/'
4.3 Spectrum : Cas d'Usage (Chaud vs Froid)

Spectrum est la solution "Lakehouse" d'AWS. Il permet de joindre (JOIN) des données "chaudes" (rapides, locales) avec des données "froides" (lentes, S3).

Exemple (Ventes + Logs)

ProblĂšme : Vous voulez analyser les ventes (1 To, table "chaude") et les croiser (JOIN) avec les logs web bruts (5 Po, table "froide").

Sans Spectrum : Vous devez COPY 5 Po de S3 vers Redshift (coût/temps impossible).

Avec Spectrum (JOIN Fédéré)
  • ventes_prod (Table Locale RA3, 1 To, Chaude/Rapide)
  • logs_s3 (Table Externe (Spectrum), 5 Po, Froide/S3)
SELECT
    v.commande_id,
    l.user_agent
FROM
    ventes_prod AS v
JOIN
    schema_s3.logs_externes AS l
    ON v.user_id = l.user_id
WHERE
    v.date > '2025-11-01'
AND l.date_partition = '2025-11-01'

Flux : Redshift (Leader) est assez intelligent pour :

  1. Scanner (rapidement) ventes_prod (local).
  2. Pousser (Pushdown) le filtre (user_id) vers Spectrum.
  3. Spectrum (couche compute S3) scanne S3 (Parquet) et ne renvoie que les lignes pertinentes.
  4. Le Leader Node fait le JOIN final.

5.1 Ingestion : Commande COPY (Batch)

La commande COPY est la méthode principale et la plus performante (Bulk) pour charger (ingérer) des données dans une table Redshift (stockage local).

Fonctionnement (ParallĂšle)

COPY est parallélisé. Le Leader Node demande à tous les Compute Nodes (Slices) de lire (en parallÚle) des morceaux des fichiers (depuis S3) et de les ingérer dans leur stockage local.

Exemple (COPY depuis S3)
COPY ma_table
FROM 's3://mon-bucket/data/mon_fichier.parquet'
IAM_ROLE 'arn:aws:iam::...'
FORMAT AS PARQUET;

-- (Exemple CSV)
COPY ma_table
FROM 's3://mon-bucket/data/mon_fichier.csv'
IAM_ROLE 'arn:aws:iam::...'
FORMAT AS CSV
DELIMITER ','
IGNOREHEADER 1;

Bonne Pratique : Pour une performance maximale, chargez plusieurs fichiers (compressés/gzip) de taille similaire (1MB-1GB), idéalement un multiple du nombre de Slices (2.2) du cluster.

5.2 Gestion : WLM (Workload Management)

WLM (Workload Management) est le "contrĂŽleur de trafic" (QoS) de Redshift. Il gĂšre la prioritĂ© et la concurrence des requĂȘtes.

Fonctionnement (Files d'attente - Queues)

WLM (par dĂ©faut "Auto WLM") analyse les requĂȘtes et les place dans des files d'attente (Queues) (pools) avec des prioritĂ©s diffĂ©rentes.

Exemple (Simplifié) :

  • Queue 1 (Superuser) : (PrioritĂ© Max) RĂ©servĂ©e Ă  root (Admin).
  • Queue 2 (BI Dashboards) : (PrioritĂ© Haute) (ex: USER GROUP 'bi_users'). Donnez 50% de la RAM.
  • Queue 3 (ETL Jobs) : (PrioritĂ© Basse) (ex: USER GROUP 'etl_users'). Donnez 30% de la RAM.
  • Queue 4 (Data Science) : (PrioritĂ© Basse) (ex: USER GROUP 'ds_users'). Donnez 20% de la RAM.

Résultat : Si l'ETL (lourd) tourne, il ne peut pas saturer la RAM/CPU allouée à la queue "BI", garantissant que les dashboards (PDG) restent rapides.

5.3 Gestion : Concurrency Scaling

C'est la réponse "Auto-scale" de Redshift (similaire au "Multi-Cluster Warehouse" (4.2) de Snowflake).

Le ProblĂšme (Pics de Concurrence)

Lundi 9h00. Votre cluster (ex: 4 nƓuds) est saturĂ©. Les requĂȘtes (BI) sont mises en file d'attente (Queued) par WLM (5.2).

La Solution (Scaling ÉphĂ©mĂšre)

Si Concurrency Scaling (Scaling de Concurrence) est activé :

  1. Redshift (WLM) détecte la file d'attente.
  2. Il dĂ©marre (spin-up) automatiquement un nouveau "Cluster de Concurrence" (Ă©phĂ©mĂšre) (ex: 4 nƓuds) en quelques secondes.
  3. Il route les requĂȘtes (en attente) vers ce nouveau cluster.
  4. (Si la charge continue) Il démarre un 3Úme, 4Úme... cluster (jusqu'à 10 par défaut).
  5. (Quand le pic est passĂ©) Il arrĂȘte automatiquement les clusters Ă©phĂ©mĂšres.

Facturation : Facturé à la seconde (similaire à Snowflake). (AWS offre 1 heure "gratuite" par jour pour 97% des cas d'usage).

6.1 Maintenance : VACUUM (Crucial)

Le PiÚge de Redshift : Redshift (basé sur Postgres) utilise une architecture MVCC (Multiversion Concurrency Control). Les DELETE et UPDATE ne suppriment/modifient pas les données physiquement.

  • DELETE FROM table... : Marque simplement les lignes comme "mortes". (Elles prennent toujours de la place).
  • UPDATE table... : Fait un DELETE (marque "morte") + un INSERT (nouvelle ligne).

Conséquence : La table "gonfle" (bloat). Les scans (SELECT) deviennent lents (car ils doivent lire les lignes "mortes" et les "ignorer").

Solution : VACUUM

VACUUM est une opération de maintenance (lourde, I/O) qui nettoie la table.

-- 1. Récupérer l'espace (DELETE)
--    (Supprime physiquement les lignes "mortes")
VACUUM DELETE ONLY ma_table;

-- 2. Re-Trier (SORT)
--    (RĂ©-applique le SORTKEY (3.3)
--     (aprĂšs des INSERTs massifs))
VACUUM SORT ONLY ma_table;

-- 3. (Le "Full") (Fait les deux)
VACUUM FULL ma_table;

Note : Redshift (moderne) exécute un VACUUM DELETE automatiquement (en arriÚre-plan). Le VACUUM SORT (ou FULL) reste souvent manuel (ou planifié) aprÚs des COPY massifs.

6.2 Maintenance : ANALYZE

Le PiĂšge n°2 : Le Leader Node (2.1) (l'Optimizer) a besoin de Statistiques Ă  jour pour crĂ©er des plans de requĂȘte efficaces (ex: "Combien de lignes ? Quelle est la cardinalitĂ© (valeurs uniques) ?").

Si vous chargez (COPY) 1 Milliard de lignes, le Leader Node (sans ANALYZE) pense toujours que la table est vide.

La Solution : ANALYZE

La commande ANALYZE (ou ANALYSE) scanne (échantillonne) la table et met à jour les statistiques (métadonnées) utilisées par l'Optimizer.

-- (AprĂšs un 'COPY' ou 'INSERT' massif)
ANALYZE ma_table;

SymptĂŽme (Sans ANALYZE) : Une requĂȘte JOIN qui devrait prendre 1 seconde (ex: Nested Loop) prend 1 heure (ex: Hash Join), car l'Optimizer a choisi le mauvais plan d'exĂ©cution (basĂ© sur des stats obsolĂštes).

6.3 Admin Cheat-sheet (SQL)
-- --- GESTION (Cluster) ---
CREATE WAREHOUSE my_wh WITH
  WAREHOUSE_SIZE = 'LARGE'
  AUTO_SUSPEND = 600;

ALTER WAREHOUSE my_wh SET WAREHOUSE_SIZE = 'XLARGE';


-- --- INGESTION (COPY) ---
COPY users
FROM 's3://my-bucket/users_data.parquet'
IAM_ROLE 'arn:aws:iam::...'
FORMAT AS PARQUET;


-- --- MAINTENANCE (Cruciale !) ---

-- (Supprimer les lignes "mortes")
VACUUM DELETE ONLY my_table;

-- (Re-trier la table selon le SORTKEY)
VACUUM SORT ONLY my_table;

-- (Mettre Ă  jour les stats pour l'Optimizer)
ANALYZE my_table;


-- --- OPTIMISATION (Définition) ---
CREATE TABLE sales (
  id INT,
  user_id INT,
  sale_date DATE
)
DISTSTYLE KEY -- (DISTKEY = 3.2)
DISTKEY (user_id)
SORTKEY (sale_date); -- (SORTKEY = 3.3)


-- --- REDSHIFT SPECTRUM (4.x) ---

-- (Créer le 'contexte' S3)
CREATE EXTERNAL SCHEMA s3_logs
FROM DATA CATALOG
DATABASE 'my_glue_db'
IAM_ROLE 'arn:aws:iam::...'
CREATE EXTERNAL DATABASE IF NOT EXISTS;

-- (Lire la table S3)
SELECT COUNT(*) FROM s3_logs.my_raw_logs;

-- (JOIN Local (ventes) + S3 (logs))
SELECT *
FROM ventes AS v
JOIN s3_logs.my_raw_logs AS l
  ON v.user_id = l.user_id
WHERE v.sale_date > '2025-01-01';