La Copy activity in una Data pipeline
In Microsoft Fabric la Copy activity è l’attività delle Data pipeline (l’esperienza Data Factory integrata in Fabric) dedicata allo spostamento dati source-to-sink. Definisce tre elementi chiave: una source (con il relativo connection, ad esempio Azure SQL Database, un file in OneLake, un’API REST, un database on-premises via on-premises data gateway), una sink di destinazione (tipicamente una tabella Lakehouse, un Warehouse o file Parquet), e un mapping fra colonne.
La Copy activity non è pensata per trasformazioni complesse: sposta e, al più, converte formati e tipi. Per logica di trasformazione si usano Dataflow Gen2, notebook Spark o attività T-SQL a valle. Nell’architettura tipica, la Copy activity porta i dati grezzi in un’area di staging, dove verranno poi modellati.
Perché lo staging
Caricare direttamente nelle tabelle di produzione è fragile. Un layer di staging (bronze) permette di:
- disaccoppiare l’ingestion dalla transformation, così un errore a valle non compromette la fonte;
- applicare deduplica, pulizia e conformità dei tipi prima di popolare il modello;
- rieseguire il caricamento in modo idempotente.
Full load vs incremental load
Il full load copia ogni volta l’intero dataset sorgente, sovrascrivendo la destinazione (Overwrite). È semplice e robusto, ideale per tabelle piccole o dimensioni a bassa volatilità, ma diventa insostenibile su tabelle fatti da milioni di righe: consuma Capacity Units, allunga le finestre di batch e stressa la sorgente.
L’incremental load copia solo il delta, cioè le righe nuove o modificate dall’ultima esecuzione, in modalità Append o Upsert (merge). È la scelta corretta per grandi volumi transazionali.
La high-watermark column
L’incremental load si basa su una high-watermark column: una colonna monotòna crescente che identifica “fino a dove” abbiamo già caricato. Le opzioni tipiche sono una colonna last-modified (ModifiedDate) o un identificatore incrementale. Il valore dell’ultimo caricamento va persistito in una control table (o file di stato) su Lakehouse/Warehouse.
Il pattern canonico usa più attività nella pipeline:
- una Lookup activity legge il watermark vecchio dalla control table;
- una seconda Lookup legge il max corrente dalla sorgente (nuovo watermark);
- la Copy activity esegue una query parametrica sul delta;
- una Stored procedure aggiorna la control table col nuovo watermark, solo se la copia riesce.
La query della sorgente filtra sui due estremi:
WHERE ModifiedDate > '@{activity('LookupOld').output.firstRow.WatermarkValue}'
AND ModifiedDate <= '@{activity('LookupNew').output.firstRow.MaxValue}'
Parametri e variabili per gestire il delta
Le pipeline parameters rendono la pipeline riutilizzabile su più tabelle: nome tabella, colonna watermark e schema di destinazione diventano input. Le pipeline variables (impostate con Set variable) conservano stati intermedi come i confini del delta durante l’esecuzione. Le espressioni (sintassi @activity(...).output.firstRow, @pipeline().parameters, funzioni come formatDateTime) collegano gli output di un’attività agli input della successiva. Questo consente di orchestrare, tramite ForEach, lo stesso pattern incrementale su decine di tabelle guidate da una lista di configurazione.
Preparazione per il modello dimensionale
Una volta in staging, i dati alimentano un modello star schema:
- le dimensioni (clienti, prodotti, date) si popolano tipicamente in Upsert/merge sulla business key, gestendo le variazioni con logica SCD;
- le fatti (ordini, transazioni) si popolano in Append incrementale, referenziando le surrogate key delle dimensioni.
Ordine e integrità referenziale contano: le dimensioni vanno caricate prima dei fatti, altrimenti una fact row può riferirsi a una dimension key non ancora esistente.
Trappole tipiche d’esame
- Grande tabella fatti che cresce ogni giorno, serve minimizzare il carico sulla sorgente → incremental load con high-watermark column, non full load ogni notte.
- Quale colonna scegliere come watermark? → una colonna last-modified affidabile aggiornata a ogni INSERT e UPDATE; una data d’ordine che non cambia sugli update fa perdere le modifiche.
- Righe con timestamp arretrato compaiono dopo il caricamento (late-arriving data) → usare il timestamp del sistema sorgente (non l’ora di elaborazione) e prevedere una lookback window che riprocessa un intervallo di sovrapposizione, così nessuna riga cade nel buco fra due run.
- Rischio di duplicati o righe saltate ai confini del delta → definire i boundary in modo coerente (
>sul vecchio,<=sul nuovo) e aggiornare il watermark solo dopo una Copy riuscita. - Dimensione con business key già esistente da aggiornare → sink in Upsert/merge sulla key, non in Append, per evitare duplicazione delle dimension row.