Evitare i cicli infiniti
Limiti di profondità e rilevamento dei cicli
Evitare i cicli infiniti è una lezione SQL Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento SQL Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso SQL Academy include 4 lezioni in totale.
Il problema dei cicli infiniti
Le CTE ricorsive sono potenti, ma comportano un rischio serio: se la query non raggiunge mai un caso base, continuerà all'infinito, consumando tutta la memoria disponibile e causando l'arresto della sessione del database.
Capire perché si verificano i cicli infiniti è il primo passo per prevenirli.
Quando un ciclo non termina mai
Una CTE ricorsiva entra in un ciclo indefinito quando il termine ricorsivo continua a produrre nuove righe senza mai arrivare a uno stato in cui non ne vengono generate altre.
Di solito questo accade in due situazioni: manca una condizione di terminazione, oppure è errata; oppure i dati sono ciclici, con il nodo A che punta a B e B che punta nuovamente ad A.
-- Simple recursive CTE that WOULD loop forever
-- (do NOT run this as-is; illustration only)
WITH RECURSIVE counter AS (
SELECT 1 AS n -- base case
UNION ALL
SELECT n + 1 -- recursive term
FROM counter
-- no WHERE clause to stop it!
)
SELECT n FROM counter;Aggiungere un limite di profondità
La protezione più semplice è un contatore della profondità. Aggiunga una colonna che aumenti di 1 a ogni passaggio ricorsivo, quindi interrompa la ricorsione quando supera una profondità massima.
In questo modo la terminazione è garantita indipendentemente dai dati e il limite scelto fornisce una soglia di sicurezza.
WITH RECURSIVE counter AS (
SELECT 1 AS n
UNION ALL
SELECT n + 1
FROM counter
WHERE n < 10 -- stop at depth 10
)
SELECT n FROM counter;Limite di profondità in una query gerarchica
Quando percorre una gerarchia di dipendenti, può tenere traccia della profondità insieme al percorso. La clausola WHERE depth < 5 impedisce di scendere oltre 5 livelli, anche se i dati contengono collegamenti più profondi o circolari.
CREATE TEMP TABLE employees (
id INT PRIMARY KEY,
name TEXT,
manager_id INT
);
INSERT INTO employees VALUES
(1, 'Alice', NULL),
(2, 'Bob', 1),
(3, 'Carol', 2),
(4, 'Dave', 3);
WITH RECURSIVE hierarchy AS (
SELECT id, name, manager_id, 1 AS depth
FROM employees
WHERE manager_id IS NULL -- root
UNION ALL
SELECT e.id, e.name, e.manager_id, h.depth + 1
FROM employees e
JOIN hierarchy h ON e.manager_id = h.id
WHERE h.depth < 5 -- depth limit
)
SELECT id, name, depth FROM hierarchy ORDER BY depth, id;Che cos'è il rilevamento dei cicli
Un ciclo si verifica nei dati di un grafo quando, seguendo gli archi, si torna infine a un nodo già visitato. Per esempio: A → B → C → A.
Un limite di profondità termina comunque la query in presenza di dati ciclici, ma non indica dove si trova il ciclo. Il rilevamento esplicito dei cicli sì.
CREATE TEMP TABLE edges (
from_node INT,
to_node INT
);
-- Introduce a cycle: 1->2->3->1
INSERT INTO edges VALUES
(1, 2),
(2, 3),
(3, 1), -- cycle back to 1
(1, 4); -- also a non-cyclic branch
SELECT * FROM edges;Tenere traccia dei nodi visitati con un array
Una tecnica robusta per rilevare i cicli consiste nel trasportare nella ricorsione un array degli ID dei nodi visitati. Prima di visitare il nodo successivo, verifichi se è già presente nell'array. In tal caso, lo salti.
PostgreSQL semplifica questa operazione con l'operatore ANY(array) e l'operatore || per aggiungere elementi a un array.
WITH RECURSIVE traverse AS (
-- Start from node 1
SELECT from_node,
to_node,
ARRAY[from_node] AS visited
FROM edges
WHERE from_node = 1
UNION ALL
SELECT e.from_node,
e.to_node,
t.visited || e.from_node
FROM edges e
JOIN traverse t ON e.from_node = t.to_node
WHERE NOT (e.from_node = ANY(t.visited)) -- skip visited nodes
)
SELECT from_node, to_node, visited
FROM traverse;La clausola CYCLE (PostgreSQL 14+)
PostgreSQL 14 ha introdotto una clausola CYCLE integrata per le CTE ricorsive. Aggiunge automaticamente due colonne: un flag booleano che vale true quando viene rilevato un ciclo e un array che registra il percorso seguito.
È una soluzione più pulita rispetto alla gestione manuale dell'array.
WITH RECURSIVE traverse AS (
SELECT from_node, to_node
FROM edges
WHERE from_node = 1
UNION ALL
SELECT e.from_node, e.to_node
FROM edges e
JOIN traverse t ON e.from_node = t.to_node
)
CYCLE from_node SET is_cycle USING path
SELECT from_node, to_node, is_cycle, path
FROM traverse;Combinare il limite di profondità e il rilevamento dei cicli
L'uso combinato di un limite di profondità e del rilevamento dei cicli offre la garanzia di sicurezza più elevata:
- Il limite di profondità agisce come soglia rigida, indipendentemente dalla qualità dei dati.
- Il rilevamento dei cicli si arresta immediatamente quando trova un ciclo, evitando iterazioni non necessarie.
Nelle query di produzione, applichi sempre almeno una di queste protezioni.
WITH RECURSIVE traverse AS (
SELECT from_node,
to_node,
1 AS depth,
ARRAY[from_node] AS visited
FROM edges
WHERE from_node = 1
UNION ALL
SELECT e.from_node,
e.to_node,
t.depth + 1,
t.visited || e.from_node
FROM edges e
JOIN traverse t ON e.from_node = t.to_node
WHERE t.depth < 10 -- depth limit
AND NOT (e.from_node = ANY(t.visited)) -- cycle guard
)
SELECT from_node, to_node, depth, visited
FROM traverse;Creare il percorso completo come stringa
Insieme al rilevamento dei cicli, è utile registrare l'intero percorso di attraversamento come stringa leggibile. Concatenando gli ID dei nodi e separandoli con -> è facile visualizzare o eseguire il debug del percorso seguito nel grafo.
WITH RECURSIVE traverse AS (
SELECT from_node,
to_node,
1 AS depth,
ARRAY[from_node] AS visited,
from_node::TEXT AS path_str
FROM edges
WHERE from_node = 1
UNION ALL
SELECT e.from_node,
e.to_node,
t.depth + 1,
t.visited || e.from_node,
t.path_str || ' -> ' || e.from_node::TEXT
FROM edges e
JOIN traverse t ON e.from_node = t.to_node
WHERE t.depth < 10
AND NOT (e.from_node = ANY(t.visited))
)
SELECT from_node, to_node, path_str, depth
FROM traverse
ORDER BY depth;Impostare max_recursive_iterations
Alcuni database (MariaDB, versioni precedenti di MySQL) usano una variabile di sessione per limitare la ricorsione. In PostgreSQL l'approccio equivalente consiste nell'affidarsi al contatore della profondità scritto manualmente o nell'usare timeout a livello di istruzione.
Impostare un statement_timeout è una protezione di ultima istanza che termina qualsiasi query fuori controllo dopo un intervallo di tempo stabilito.
-- PostgreSQL: set a statement timeout as a safety net
SET statement_timeout = '5s';
-- Now any query that runs longer than 5 seconds is cancelled
WITH RECURSIVE counter AS (
SELECT 1 AS n
UNION ALL
SELECT n + 1 FROM counter WHERE n < 1000000
)
SELECT MAX(n) FROM counter;
-- Reset to default when done
SET statement_timeout = '0';Scegliere il limite di profondità corretto
Non esiste un limite di profondità universale. Scelga il Suo in base alla profondità massima realistica dei dati:
- Un organigramma raramente supera 10-15 livelli: usi
depth < 20come margine di sicurezza adeguato. - Un albero del file system può raggiungere una profondità di 50-100 livelli.
- Un attraversamento di un grafo di social network è spesso limitato a 3-6 passaggi.
Imposti un limite abbastanza alto da includere i dati validi, ma abbastanza basso da rilevare tempestivamente le query fuori controllo.
-- Example: org chart with a generous but safe depth cap
WITH RECURSIVE org AS (
SELECT id, name, manager_id, 1 AS depth
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.id, e.name, e.manager_id, o.depth + 1
FROM employees e
JOIN org o ON e.manager_id = o.id
WHERE o.depth < 20 -- realistic upper bound for an org chart
)
SELECT id, name, depth
FROM org
ORDER BY depth, name;Limiti di profondità e rilevamento dei cicli
Quale tecnica dovrebbe usare?
Riepilogo: mantenere sicure le query ricorsive
Ecco un riepilogo di ciò che ha imparato per evitare i cicli infiniti nelle CTE ricorsive:
- Limite di profondità — aggiunga una colonna contatore e interrompa la ricorsione con
WHERE depth < N. È sempre efficace e facile da implementare. - Rilevamento dei cicli basato su array — conservi gli ID dei nodi visitati in un array e salti ogni nodo già presente. Si arresta al primo ciclo.
- Clausola CYCLE (PostgreSQL 14+) — sintassi integrata che automatizza il rilevamento dei cicli con le colonne
is_cycleepath. - statement_timeout — una protezione a livello di database per le query fuori controllo, non un sostituto della logica corretta.
- Combini entrambi il limite di profondità e il rilevamento dei cicli in produzione per ottenere la garanzia più elevata.
Con queste tecniche può percorrere gerarchie e grafi in tutta sicurezza, senza rischiare arresti anomali del database.
Impara SQL con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 46
- Lezioni
- 183
Domande Frequenti
La lezione «Evitare i cicli infiniti» è gratuita?
Sì — il testo completo di «Evitare i cicli infiniti» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso SQL Academy, passa a CoddyKit PRO. Il corso SQL Academy include 4 lezioni in totale.
Cosa imparerò in «Evitare i cicli infiniti»?
Limiti di profondità e rilevamento dei cicli Eserciti SQL Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare SQL Academy?
Non è richiesta alcuna esperienza precedente. SQL Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Evitare i cicli infiniti»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione SQL Academy?
Sì. Ogni lezione SQL Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Come funzionano le CTE ricorsive
- Percorrere un albero di categorie
- Generare serie e sequenze
- Evitare i cicli infiniti