Unngå uendelige løkker
Dybdegrenser og syklusdeteksjon.
Unngå uendelige løkker er en gratis leksjon i SQL Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i SQL Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i SQL Academy inneholder totalt 4 leksjoner.
Problemet med uendelige løkker
Rekursive CTE-er er kraftige, men innebærer en alvorlig risiko: Hvis spørringen aldri når et basistilfelle, vil den gå i løkke for alltid, bruke opp alt tilgjengelig minne og krasje databasesesjonen.
Å forstå hvorfor uendelige løkker oppstår, er første steg mot å forhindre dem.
Når tar en løkke aldri slutt?
En rekursiv CTE kjører i det uendelige når det rekursive leddet fortsetter å produsere nye rader uten noen gang å nå en tilstand der ingen nye rader genereres.
Dette skjer vanligvis i to situasjoner: en manglende eller feil avslutningsbetingelse, eller sykliske data der node A peker på B og B peker tilbake på 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;Legge til en dybdebegrensning
Det enkleste sikkerhetstiltaket er en dybdeteller. Legg til en kolonne som økes med 1 ved hvert rekursive trinn, og stopp når den overskrider en maksimal dybde.
Dette garanterer avslutning uavhengig av dataene, og den valgte grensen gir en sikkerhetsgrense.
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;Dybdebegrensning i en hierarkispørring
Når du traverserer et ansatthierarki, kan du spore dybden sammen med stien. WHERE depth < 5-klausulen forhindrer traversering forbi 5 nivåer, selv om dataene har dypere eller sirkulære koblinger.
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;Hva er syklusdeteksjon?
En syklus oppstår i grafdata når det å følge kanter til slutt fører tilbake til en node du allerede har besøkt. For eksempel: A → B → C → A.
En dybdebegrensning avslutter fortsatt spørringen i sykliske data, men den forteller deg ikke hvor syklusen er. Det gjør eksplisitt syklusdeteksjon.
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;Spore besøkte noder med en array
En robust teknikk for syklusdeteksjon er å føre med en array med besøkte node-ID-er gjennom rekursjonen. Før du besøker neste node, kontrollerer du om den allerede finnes i arrayet. Hvis den gjør det, hopper du over den.
PostgreSQL gjør dette enkelt med ANY(array)-operatoren og ||-operatoren for å legge til elementer i arrayet.
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;CYCLE-klausulen (PostgreSQL 14+)
PostgreSQL 14 introduserte en innebygd CYCLE-klausul for rekursive CTE-er. Den legger automatisk til to kolonner: et boolsk flagg som er true når en syklus oppdages, og en array som registrerer stien som er fulgt.
Dette er ryddigere enn å vedlikeholde arrayet manuelt.
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;Kombinere dybdebegrensning og syklusdeteksjon
Ved å bruke både en dybdebegrensning og syklusdeteksjon får du den beste sikkerheten:
- Dybdebegrensningen fungerer som en absolutt grense, uavhengig av datakvaliteten.
- Syklusdeteksjon stopper med en gang en løkke oppdages og sparer unødvendige iterasjoner.
I spørringer i produksjon bør du alltid bruke minst ett av disse sikkerhetstiltakene.
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;Bygge hele stien som en streng
Sammen med syklusdeteksjon er det nyttig å registrere hele traverseringsstien som en lesbar streng. Ved å sette sammen node-ID-er, adskilt med -> , blir det enkelt å vise eller feilsøke ruten gjennom grafen.
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;Angi max_recursive_iterations
Noen databaser (MariaDB, eldre MySQL) bruker en sesjonsvariabel til å begrense rekursjon. I PostgreSQL er den tilsvarende tilnærmingen å bruke dybdetelleren du skriver selv, eller tidsavbrudd på setningsnivå.
Å angi en statement_timeout er et sikkerhetsnett i siste instans som avslutter en spørring som løper løpsk etter en angitt tid.
-- 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';Velge riktig dybdebegrensning
Det finnes ingen universell dybdebegrensning. Velg en basert på den største realistiske dybden i dataene dine:
- Et organisasjonskart overskrider sjelden 10–15 nivåer – bruk
depth < 20som en god sikkerhetsmargin. - Et filsystemtre kan gå 50–100 nivåer dypt.
- En traversering av et sosialt nettverk begrenses ofte til 3–6 hopp.
Sett grensen høyt nok til å fange opp gyldige data, men lavt nok til å oppdage spørringer som løper løpsk tidlig.
-- 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;Dybdebegrensninger kontra syklusdeteksjon
Hvilken teknikk bør du bruke?
Oppsummering: Sikre rekursive spørringer
Her er en oppsummering av det du har lært om å unngå uendelige løkker i rekursive CTE-er:
- Dybdebegrensning – legg til en tellerkolonne og stopp med
WHERE depth < N. Alltid effektivt og enkelt å implementere. - Array-basert syklusdeteksjon – før besøkte node-ID-er videre i en array, og hopp over alle noder som allerede finnes i den. Stopper tidlig ved første syklus.
- CYCLE-klausul (PostgreSQL 14+) – innebygd syntaks som automatiserer syklussporing med
is_cycle- ogpath-kolonner. - statement_timeout – et sikkerhetsnett på databasenivå for spørringer som løper løpsk, ikke en erstatning for riktig logikk.
- Kombiner begge: dybdebegrensning og syklusdeteksjon i produksjon for best mulig garanti.
Med disse teknikkene kan du trygt traversere hierarkier og grafer uten å risikere databasekrasj.
Lær deg SQL med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 46
- Leksjoner
- 183
Ofte stilte spørsmål
Er leksjonen «Unngå uendelige løkker» gratis?
Ja – hele teksten i «Unngå uendelige løkker» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av SQL Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i SQL Academy inneholder totalt 4 leksjoner.
Hva lærer jeg i «Unngå uendelige løkker»?
Dybdegrenser og syklusdeteksjon. Du øver på SQL Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med SQL Academy?
Ingen tidligere erfaring er nødvendig. SQL Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.
Hvor lang tid tar leksjonen «Unngå uendelige løkker»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne SQL Academy-leksjonen?
Ja. Alle SQL Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Slik fungerer rekursive CTE-er
- Gå gjennom et kategoritre
- Generere serier og sekvenser
- Unngå uendelige løkker