Una guida dettagliata riga per riga sul passaggio di una stored procedure legacy a Databricks. Cursori, tabelle temporanee e transazioni multi-istruzione vengono migrati come SQL nell'ambito della migrazione del data warehouse.
Da qualche parte nel vostro data warehouse, centinaia di stored procedure si attivano ogni notte e, silenziosamente, mantengono attiva l'azienda. Sono state scritte anni fa da un gruppo di sviluppatori SQL che hanno ormai lasciato l'azienda da tempo. Hanno cursori annidati. Creano tabelle temporanee al volo. Raggruppano gli aggiornamenti su più tabelle in una singola transazione. E intorno alla riga 47, c'è un commento che dice semplicemente: “Non toccare questo.” Nessuno capisce più a fondo queste procedure. Eppure, tutti dipendono da esse. La dashboard dei ricavi, la chiusura finanziaria, il report delle operazioni: tutti, in un modo o nell'altro, riconducono a questi livelli di logica di business SQL procedurale.
Spostare i dati nel lakehouse è un processo ormai consolidato. L'ostacolo principale è sempre stato il nucleo procedurale di qualsiasi migrazione di data warehouse: le stored procedure, la gestione delle transazioni, le tabelle temporanee, il flusso di controllo e il fatto che gran parte dell'azienda si affidi ancora a competenze SQL. Ogni volta che si prospettava una migrazione, queste procedure erano la prima cosa che tutti indicavano: “Non possiamo migrare finché non riusciremo a eseguirle con modifiche minime. La nostra azienda è ancora fortemente basata su SQL.”
Abbiamo quindi deciso di prendere un caso d'uso simile a quello a cui probabilmente state pensando in questo momento, una procedura composita che abbiamo riscontrato in diverse migrazioni, e di mostrarlo, passo dopo passo, sul Lakehouse. Questo esempio si basa su un caso d'uso di migrazione da Oracle, ma può essere applicato a qualsiasi data warehouse (legacy o basato su cloud).
Questa procedura di esempio elabora gli ordini giornalieri. Esegue lo staging degli ordini non elaborati in una tabella temporanea, li convalida rispetto all'anagrafica clienti, esegue un ciclo sugli errori per registrare singolarmente ogni rifiuto, quindi aggiorna i riepiloghi dei ricavi regionali e contrassegna tutti gli ordini come elaborati, il tutto all'interno di una transazione che esegue il rollback in caso di errore.
Un unico job notturno che non deve assolutamente interrompersi.
In passato, migrare questa procedura significava riscriverla interamente in Python e Spark. Settimane di lavoro, nuovi bug da scovare e un team SQL che non era più in grado di gestire la propria logica di business.
Non l'abbiamo riscritta. L'abbiamo tradotta.
Ogni procedura inizia con una firma e una rete di sicurezza. Il sistema legacy racchiudeva il corpo in BEGIN ... EXCEPTION ... END. Databricks utilizza invece DECLARE EXIT HANDLER FOR SQLEXCEPTION; stessa idea, sintassi leggermente diversa. Ipotizziamo che il catalogo e lo schema appropriati siano già stati impostati nella sessione.
La grande differenza non sta nel codice, ma in ciò che accade dopo il deployment. Su Databricks, la procedura viene registrata in Unity Catalog. Ottiene controlli di accesso, derivazione dei dati (lineage) a livello di colonna e rilevabilità in ogni workspace. Nel sistema attuale, risiedeva in uno schema di cui solo tre persone conoscevano la password.
Legacy | Databricks |
CREATE OR REPLACE PROCEDURE name IS | CREATE OR REPLACE PROCEDURE [IF NOT EXISTS] <catalog>.<schema>.<procedure_name> ( [ procedure_parameter [, ...] ] ) [ characteristic [...] ] LANGUAGE SQL SQL SECURITY { INVOKER | DEFINER } AS BEGIN |
v_id NUMBER; prima di BEGIN | DECLARE v_id INT; all'interno di BEGIN |
EXCEPTION WHEN OTHERS THEN | DECLARE EXIT HANDLER FOR SQLEXCEPTION |
Riferimento: docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-ddl-create-procedure
La procedura originale crea due tabelle temporanee per lo staging e gli errori di validazione. Rappresentano lo spazio di lavoro temporaneo da cui dipende il resto della logica.
Su Databricks, questa diventa una delle parti più semplici della migrazione. Nessun EXECUTE IMMEDIATE. Nessun ON COMMIT PRESERVE ROWS. La direttiva CREATE TEMP TABLE con ambito sessione è la sostituzione diretta, con un piccolo avvertimento: CREATE OR REPLACE TEMP TABLE non è ancora supportata, quindi esegui prima un drop se hai bisogno di rieseguire lo script nella stessa sessione.
Riferimento: docs.databricks.com/aws/en/tables/temporary-tables
Questo era il pezzo che tutti pensavano avrebbe richiesto una riscrittura. La procedura originale scorre gli errori di validazione uno ad uno, rifiuta ogni ordine non valido e ne registra il motivo. Un classico pattern a cursore. Decenni di memoria muscolare legacy (Oracle, ad esempio).
Lo scripting SQL di Databricks supporta i cursori in modo nativo, OPEN, FETCH e CLOSE a partire da Runtime 18.1. L'attributo %NOTFOUND diventa un CONTINUE HANDLER FOR NOT FOUND. Le etichette dei cicli e LEAVE sostituiscono EXIT WHEN.
Il controllo condizionale (se non ci sono righe da elaborare, salta e registra) è rimasto quasi identico. SELECT ... INTO diventa SET var = (SELECT ...). Tutto il resto è identico.
Il nostro scripting SQL supporta l'intero toolkit procedurale: IF/ELSE, WHILE, FOR, LOOP, REPEAT, LEAVE, ITERATE, SIGNAL/RESIGNAL. Se la tua codebase contiene script Teradata BTEQ con direttive .GOTO e .LABEL , queste si mappano su cicli etichettati utilizzando LEAVE and ITERATE.
Riferimento: docs.databricks.com/aws/en/sql/language-manual/sql-ref-scripting
Questo era l'ultimo tassello, quello che ha reso la migrazione effettivamente fattibile. La procedura originale aggiorna regional_revenue, contrassegna gli ordini come elaborati e registra il batch. Se una qualsiasi parte fallisce, viene eseguito il rollback di tutto.
Sul sistema legacy, si tratta di una transazione implicita con un COMMIT esplicito. Su Databricks, BEGIN ATOMIC ... END offre la stessa semantica, commit automatico in caso di successo, rollback automatico in caso di errore, con un vantaggio significativo: il rilevamento dei conflitti a livello di riga. I batch simultanei che scrivono sulla stessa tabella entrano in conflitto solo se interessano le stesse righe. Ad esempio, sia Oracle che Snowflake utilizzano il blocco a livello di tabella, il che forza l'esecuzione seriale.
L'istruzione MERGE può essere migrata su Databricks così com'è. Il COMMIT esplicito è scomparso poiché viene gestito da BEGIN ATOMIC. E il team ha smesso di preoccuparsi che i job batch simultanei si ostacolassero a vicenda.
Due note pratiche quando si adotta questo pattern:
Riferimento: docs.databricks.com/aws/en/transactions/
Stessa logica di business. Stesso flusso di controllo. Gestito da Unity Catalog.
Per eseguirlo all'interno di una transazione, racchiudi la chiamata:
Le tempistiche di migrazione per questi programmi possono essere ridotte del 50-75%, anche per stored procedure complesse con pesanti dipendenze da pacchetti PL/SQL. Questa efficienza deriva da un processo di traduzione meccanica che preserva la logica di business originale, garantendo che il team SQL possa continuare senza problemi il proprio lavoro di manutenzione. Oltre alla migrazione stessa, i team ottengono un nuovo potente vantaggio: una piattaforma unificata in cui gli stessi dati governati alimentano le loro dashboard, i modelli di machine learning e le iniziative di AI.
L'unico modo per sapere se le tue procedure vengono tradotte correttamente è provarne una. Scegli la stored procedure più piccola del tuo batch, preferibilmente una che nessuno ama sottoporre a debug. Crea un progetto di migrazione nel tuo workspace e inizia a usare Agentic Code Convertor!
(Questo post sul blog è stato tradotto utilizzando strumenti basati sull'intelligenza artificiale) Post originale
Iscriviti al nostro blog e ricevi gli ultimi articoli direttamente nella tua casella di posta.