In SQL esistono diversi modi per realizzare calcoli iterativi/ricorsivi:
WITH RECURSIVE) — utilizzati per attività come l'attraversamento di gerarchie (alberi, grafi, catene di riferimenti).Quando utilizzare un CTE ricorsivo:
Esempio:
WITH RECURSIVE tree AS ( SELECT id, parent_id, name, 1 AS level FROM categories WHERE parent_id IS NULL UNION ALL SELECT c.id, c.parent_id, c.name, t.level + 1 FROM categories c JOIN tree t ON c.parent_id = t.id ) SELECT * FROM tree;
Se il CTE ricorsivo non risolve il problema o se i dati sono troppo voluminosi, si applicano altri meccanismi (ad esempio, elaborazione esterna, tabelle temporanee o algoritmi specializzati al di fuori di SQL).
Può un CTE ricorsivo portare a un'esecuzione infinita? Come prevenirlo?
Risposta:
Sì, se nel grafo ci sono cicli (ad esempio, parent_id si riferisce di nuovo a un discendente), il CTE ricorsivo può entrare in un ciclo. La maggior parte dei DBMS supporta la limitazione del numero massimo di livelli di ricorsione (MAXRECURSION per MS SQL o un'opzione simile). È buona pratica limitare sempre la profondità della ricorsione.
-- MS SQL Server OPTION (MAXRECURSION 100)
Storia
In un progetto finanziario calcolavamo il saldo finale tramite catene di conti correlati (parent-child) tramite un CTE ricorsivo. Uno degli utenti creò un ciclo nella struttura (un genitore divenne il proprio discendente). La query ha cominciato a essere eseguita all'infinito, sovraccaricando il server. Aggiungemmo un controllo sui cicli e MAXRECURSION, il problema si risolse.
Storia
Nel sistema di gestione delle attività, lo stato delle attività dipendenti veniva calcolato tramite elaborazione a cursore. Dopo la migrazione a CTE ricorsivi non si era pensato a prevedere indici ottimali su parent_id — le prestazioni sono diminuite di 5 volte, poiché a ogni passaggio si verificavano costly join.
Storia
La query per attraversare l'albero delle categorie tramite cursore funzionava correttamente, ma impiegava 7 minuti per 100.000 righe. Riscrivemmo utilizzando un CTE ricorsivo, considerato "lento", — ottimizzammo e ottenemmo lo stesso risultato in 5 secondi grazie all'ottimizzazione del motore di lavoro con insiemi.