Snowflake n est pas juste un data warehouse SQL. En entretien Senior, on eval...
Qu'est-ce qu'un Stream Snowflake ? Quelle est la différence entre APPEND_ONLY et DEFAULT ?
-- Créer un stream sur une table source
CREATE STREAM orders_stream ON TABLE orders
APPEND_ONLY = FALSE; -- capture INSERT + UPDATE + DELETE
-- APPEND_ONLY = TRUE : capture uniquement les INSERT (plus performant)
-- APPEND_ONLY = FALSE : capture INSERT + UPDATE + DELETE via METADATA$ACTION
-- Consommer le stream dans un MERGE
MERGE INTO orders_target AS t
USING (
SELECT order_id, customer_id, amount,
METADATA$ACTION, -- INSERT ou DELETE
METADATA$ISUPDATE -- True si c'est un UPDATE (représenté par DELETE+INSERT)
FROM orders_stream
) AS s ON t.order_id = s.order_id
WHEN MATCHED AND s.METADATA$ACTION = 'DELETE' AND NOT s.METADATA$ISUPDATE
THEN DELETE
WHEN MATCHED AND s.METADATA$ACTION = 'INSERT' AND s.METADATA$ISUPDATE
THEN UPDATE SET t.amount = s.amount, t.customer_id = s.customer_id
WHEN NOT MATCHED AND s.METADATA$ACTION = 'INSERT'
THEN INSERT (order_id, customer_id, amount) VALUES (s.order_id, s.customer_id, s.amount);
-- Vérifier si le stream a des données à consommer
SELECT SYSTEM$STREAM_HAS_DATA('orders_stream');Comment combinez-vous Streams et Tasks pour un pipeline CDC automatique ?
-- Task planifiée toutes les heures
CREATE OR REPLACE TASK refresh_aggregates
WAREHOUSE = 'ETL_WH'
SCHEDULE = 'USING CRON 0 * * * * UTC'
ERROR_INTEGRATION = 'my_notification_int' -- alerte en cas d'erreur
AS
CALL refresh_daily_revenue();
ALTER TASK refresh_aggregates RESUME;
-- Task déclenchée automatiquement par un Stream (quand nouvelles données)
CREATE OR REPLACE TASK process_new_orders
WAREHOUSE = 'ETL_WH'
AFTER refresh_aggregates -- task parente (DAG de tasks)
WHEN SYSTEM$STREAM_HAS_DATA('orders_stream')
AS
MERGE INTO orders_processed AS t
USING orders_stream AS s ON t.order_id = s.order_id
WHEN MATCHED THEN UPDATE SET t.amount = s.amount
WHEN NOT MATCHED THEN INSERT VALUES (s.order_id, s.customer_id, s.amount);
-- Surveiller les tasks
SELECT *
FROM TABLE(INFORMATION_SCHEMA.TASK_HISTORY(
SCHEDULED_TIME_RANGE_START => DATEADD('hour', -24, CURRENT_TIMESTAMP)
))
ORDER BY SCHEDULED_TIME DESC;Qu'est-ce qu'une Dynamic Table ? Quand l'utiliser à la place d'un modèle dbt ?
-- Créer une Dynamic Table
CREATE OR REPLACE DYNAMIC TABLE analytics.daily_revenue
TARGET_LAG = '1 hour' -- fraîcheur souhaitée
WAREHOUSE = ETL_WH
AS
SELECT
DATE(order_date) AS day,
region,
SUM(amount) AS revenue,
COUNT(*) AS order_count
FROM raw.orders
GROUP BY 1, 2;
-- Snowflake gère automatiquement le refresh incrémental
-- Pas besoin de scheduler externe ni de logique incremental manuelle
-- Vérifier le statut
SHOW DYNAMIC TABLES LIKE 'daily_revenue';Qu'est-ce que le Zero-Copy Cloning ? Comment l'utilisez-vous en pratique ?
-- Cloner une base entière en quelques secondes, sans copier les données
CREATE DATABASE staging_clone CLONE production;
-- Les données ne sont PAS dupliquées. Partage des micro-partitions.
-- Écriture en staging → copie uniquement des partitions modifiées (copy-on-write)
-- Use cases :
-- 1. Test de migration sans risque
-- 2. Environnement de dev avec données de production
-- 3. Snapshot rapide avant une opération risquée
-- Time Travel : requêter les données passées
SELECT * FROM orders AT(TIMESTAMP => '2025-01-01 00:00:00'::TIMESTAMP_TZ);
SELECT * FROM orders BEFORE(STATEMENT => 'last_bad_query_id');
-- Restaurer une table depuis Time Travel
CREATE TABLE orders_restored CLONE orders
AT(TIMESTAMP => '2025-01-01 00:00:00'::TIMESTAMP_TZ);
-- Undrop : restaurer une table supprimée (dans la fenêtre Time Travel)
DROP TABLE orders;
UNDROP TABLE orders; -- fonctionne pendant 7 à 90 jours selon la configQu'est-ce que Snowpark ? Quand l'utiliser à la place d'un script Python externe ?
from snowflake.snowpark import Session
from snowflake.snowpark.functions import col, sum as sum_, when
session = Session.builder.configs({
"account": "mon-compte",
"user": "data_engineer",
"private_key": load_private_key()
}).create()
# DataFrame API Snowpark - s'exécute dans Snowflake (pas en local)
df = session.table("raw.orders")
result = (
df.filter(col("status") == "completed")
.group_by("region")
.agg(
sum_("amount").alias("total_revenue"),
count("*").alias("order_count")
)
.sort("total_revenue", ascending=False)
)
result.write.save_as_table("analytics.revenue_by_region", mode="overwrite")Quelles sont vos pratiques pour optimiser les coûts Snowflake en production ?
-- Resource monitor : alerter à 80% et suspendre à 100% du budget mensuel
CREATE OR REPLACE RESOURCE MONITOR monthly_budget
WITH CREDIT_QUOTA = 500 -- 500 crédits/mois
TRIGGERS
ON 80 PERCENT DO NOTIFY
ON 100 PERCENT DO SUSPEND_IMMEDIATE;
ALTER WAREHOUSE ETL_WH SET RESOURCE_MONITOR = monthly_budget;| Niveau | Maîtrise | Signal GO | NO-GO |
|---|---|---|---|
| Confirmé | Streams basiques, Tasks, Time Travel, Zero-Copy Clone | A configuré un Stream + Task pour du CDC, a utilisé Time Travel pour débugger | Ne sait pas ce qu'est un Stream Snowflake |
| Senior | Dynamic Tables, Snowpark, optimisation coûts, resource monitors | A déployé des Dynamic Tables, utilise Snowpark, a mis en place un resource monitor | N'a jamais touché à Snowpark ni aux Dynamic Tables |
Premier entretien gratuit. Rapport GO/NO-GO sous 48h.