Nel dominio “Prepare and serve data” di DP-600 la domanda ricorrente è sempre la stessa: posso scrivere qui, o solo leggere? Sapere con precisione dove finisce il T-SQL di scrittura è ciò che separa una risposta corretta da un distrattore ben costruito.

Due motori SQL, due contratti diversi

In Microsoft Fabric esistono due superfici T-SQL, entrambe raggiungibili con la stessa connection string TDS e gli stessi strumenti (SSMS, Azure Data Studio, portale):

Caratteristica Warehouse SQL analytics endpoint (Lakehouse)
SELECT
INSERT / UPDATE / DELETE / TRUNCATE No
CREATE TABLE, CTAS, SELECT INTO No
COPY INTO No
Transazioni multi-table (ACID, snapshot isolation) Solo lettura
CREATE VIEW / FUNCTION / PROCEDURE Sì (solo logica di lettura)
RLS, CLS, dynamic data masking
Storage sottostante Delta in OneLake Delta in OneLake

Il punto chiave: entrambi scrivono e leggono Delta Lake su OneLake, quindi la differenza non è il formato ma il contratto di scrittura. Il lakehouse si popola con Spark, Dataflow Gen2, pipeline o shortcut; l’endpoint SQL è una proiezione read-only di quelle tabelle Delta.

Cosa puoi comunque fare sull’endpoint

L’endpoint non è “inutile per il DDL”: puoi creare view, funzioni scalari e table-valued e stored procedure purché contengano solo operazioni di lettura. È lì che si costruisce il semantic layer SQL sopra il lakehouse e si applicano le policy di sicurezza a livello di riga e colonna.

Limiti T-SQL del warehouse (i distrattori classici)

Il warehouse non è SQL Server. Non sono supportati:

  • Constraint enforced: PRIMARY KEY, UNIQUE e FOREIGN KEY esistono solo come metadati NOT ENFORCED; l’unicità va garantita dalla pipeline. CHECK constraint non supportati.
  • IDENTITY, SEQUENCE, colonne calcolate, trigger, indici (nessun clustered/nonclustered index: le performance dipendono da statistiche e ordinamento dei file).
  • Tipi di dato legacy: money, smallmoney, datetime, text/ntext, image, xml, sql_variant, tipi spaziali, rowversion.
  • Livelli di isolamento diversi da snapshot: niente READ COMMITTED con lock, niente SERIALIZABLE, niente READ UNCOMMITTED con semantica di dirty read.
  • Query cross-workspace: i nomi a tre parti funzionano solo all’interno dello stesso workspace.

Restano invece supportati e vengono spesso sottovalutati: MERGE, CTAS, SELECT INTO, TRUNCATE TABLE, tabelle temporanee di sessione (#temp), VARCHAR(MAX), BEGIN TRAN/COMMIT su più tabelle e sp_rename.

Cross-database query nello stesso workspace

Warehouse ed endpoint SQL condividono lo stesso motore, quindi puoi fare join diretti con nomi a tre parti, senza copiare dati e senza linked server:

-- Eseguita dal Warehouse: legge dal Lakehouse, scrive nel Warehouse
INSERT INTO dbo.FactSalesEnriched (OrderId, CustomerId, Amount, Region)
SELECT  o.OrderId,
        o.CustomerId,
        o.Amount,
        c.Region
FROM    SalesLakehouse.dbo.orders_bronze AS o
JOIN    dbo.DimCustomer               AS c
        ON c.CustomerId = o.CustomerId;

La regola operativa: la lettura è bidirezionale, la scrittura solo verso il warehouse. Se ti serve materializzare il risultato di un join, la destinazione deve essere una tabella del warehouse (o del lakehouse, ma tramite Spark/pipeline).

Ritardo di sincronizzazione dei metadati Delta

L’endpoint SQL non legge i file Delta in tempo reale: un processo in background sincronizza i metadati delle tabelle Delta nel catalogo SQL. Conseguenze pratiche:

  • Dopo una scrittura Spark, la tabella o le nuove righe possono non essere immediatamente visibili via T-SQL (tipicamente secondi, ma con molte tabelle o scritture frequenti la latenza cresce).
  • In una pipeline che fa “Notebook Spark → Stored procedure SQL”, va inserito un passo di refresh dei metadati dell’endpoint (azione di sync nel portale o API REST) prima dello step SQL, altrimenti si legge uno stato stale.
  • Tabelle con feature Delta o tipi non supportati (es. tipi complessi/nested, alcune feature del protocol) possono comparire in errore o non comparire affatto: la soluzione è esporre una vista appiattita o riscrivere la tabella in formato compatibile.
  • I dati caricati come file (CSV/Parquet non registrati come tabella Delta) non sono visibili all’endpoint: vanno prima convertiti in tabella Delta.

Trappole tipiche d’esame

  • Scenario: gli analisti devono eseguire UPDATE correttivi su una dimensione già caricata nel lakehouse, usando solo T-SQL. → Risposta giusta: caricare/spostare la tabella in un Warehouse; l’endpoint SQL del lakehouse è read-only e nessun grant o ruolo lo rende scrivibile.
  • Scenario: serve incapsulare una logica di reporting sul lakehouse riutilizzabile da Power BI, senza modificare i dati. → Risposta giusta: creare view o stored procedure di sola lettura sull’endpoint SQL (non serve un warehouse aggiuntivo).
  • Scenario: una pipeline deve aggiornare due tabelle e garantire che o entrambe riescano o nessuna. → Risposta giusta: transazione esplicita multi-table nel warehouse; l’endpoint e le scritture Spark non offrono transazioni cross-table.
  • Scenario: dopo un notebook Spark, la stored procedure a valle non trova le righe nuove. → Risposta giusta: attendere/forzare la sincronizzazione dei metadati Delta dell’endpoint SQL, non ricreare la tabella.
  • Scenario: il team chiede di garantire l’unicità di una chiave con un UNIQUE constraint nel warehouse. → Risposta giusta: i constraint sono NOT ENFORCED; la deduplica va gestita nella logica di caricamento (es. MERGE o dedup a monte).
  • Scenario: join fra un warehouse in Workspace A e un lakehouse in Workspace B con nomi a tre parti. → Risposta giusta: non supportato — usare una shortcut OneLake per portare i dati nello stesso workspace.