0Pricing
SQL Academy · Lección

Cómo evitar bucles infinitos

Límites de profundidad y detección de ciclos

Cómo evitar bucles infinitos es una lección gratuita de SQL Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de SQL Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de SQL Academy incluye 4 lecciones en total.

El problema del bucle infinito

Las CTE recursivas son potentes, pero conllevan un riesgo importante: si la consulta nunca alcanza un caso base, se ejecutará indefinidamente, consumirá toda la memoria disponible y provocará el cierre de la sesión de la base de datos.

Comprender por qué se producen los bucles infinitos es el primer paso para prevenirlos.

¿Cuándo no termina un bucle?

Una CTE recursiva entra en un bucle indefinido cuando el término recursivo sigue produciendo filas nuevas sin llegar nunca a un estado en el que no se generen más filas.

Esto suele ocurrir en dos situaciones: cuando falta la condición de terminación o es incorrecta, o cuando hay datos cíclicos en los que el nodo A apunta a B y B vuelve a apuntar a 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;

Añadir un límite de profundidad

La protección más sencilla es un contador de profundidad. Añada una columna que se incremente en 1 en cada paso recursivo y deténgase cuando supere una profundidad máxima.

Esto garantiza la terminación independientemente de los datos, y el límite elegido proporciona un tope de seguridad.

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;

Límite de profundidad en una consulta jerárquica

Al recorrer una jerarquía de empleados, puede seguir la profundidad junto con la ruta. La cláusula WHERE depth < 5 impide recorrer más de 5 niveles, incluso si los datos contienen enlaces más profundos o circulares.

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;

¿Qué es la detección de ciclos?

Un ciclo se produce en los datos de un grafo cuando seguir las aristas acaba llevando a un nodo que ya ha visitado. Por ejemplo: A → B → C → A.

Un límite de profundidad sigue terminando la consulta en datos cíclicos, pero no le indica dónde está el ciclo. La detección explícita de ciclos sí lo hace.

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;

Registrar los nodos visitados con un array

Una técnica sólida para detectar ciclos consiste en transportar un array de identificadores de nodos visitados durante la recursión. Antes de visitar el siguiente nodo, compruebe si ya se encuentra en el array. Si es así, omítalo.

PostgreSQL facilita esta tarea con el operador ANY(array) y el operador || para añadir elementos al 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 cláusula CYCLE (PostgreSQL 14+)

PostgreSQL 14 introdujo una cláusula integrada CYCLE para las CTE recursivas. Añade automáticamente dos columnas: un indicador booleano que es true cuando se detecta un ciclo y un array que registra la ruta seguida.

Esto resulta más limpio que mantener el array manualmente.

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;

Combinar el límite de profundidad y la detección de ciclos

Utilizar conjuntamente un límite de profundidad y la detección de ciclos proporciona la mayor garantía de seguridad:

  • El límite de profundidad actúa como un tope estricto independientemente de la calidad de los datos.
  • La detección de ciclos detiene la ejecución en cuanto encuentra un bucle, lo que evita iteraciones innecesarias.

En las consultas de producción, aplique siempre al menos una de estas protecciones.

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;

Construir la ruta completa como una cadena

Además de detectar ciclos, resulta útil registrar la ruta completa del recorrido como una cadena legible. Concatenar los identificadores de los nodos separados por -> facilita mostrar o depurar la ruta seguida por el 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;

Configurar max_recursive_iterations

Algunas bases de datos (MariaDB y versiones antiguas de MySQL) utilizan una variable de sesión para limitar la recursión. En PostgreSQL, el enfoque equivalente consiste en utilizar el contador de profundidad que escribe usted mismo o tiempos de espera a nivel de sentencia.

Establecer un statement_timeout es una red de seguridad de último recurso que termina cualquier consulta descontrolada después de un tiempo establecido.

-- 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';

Elegir el límite de profundidad adecuado

No existe un límite de profundidad universal. Elija el suyo en función de la profundidad máxima realista de sus datos:

  • Un organigrama rara vez supera los 10-15 niveles; utilice depth < 20 como margen cómodo.
  • Un árbol del sistema de archivos puede alcanzar entre 50 y 100 niveles de profundidad.
  • El recorrido de un grafo de una red social suele limitarse a entre 3 y 6 saltos.

Establezca un límite lo bastante alto para incluir los datos válidos, pero lo bastante bajo para detectar pronto las consultas descontroladas.

-- 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;

Límites de profundidad frente a detección de ciclos

¿Qué técnica debería utilizar?

Resumen: mantener seguras las consultas recursivas

Este es un resumen de lo que ha aprendido sobre cómo evitar bucles infinitos en las CTE recursivas:

  • Límite de profundidad — añada una columna de contador y deténgase con WHERE depth < N. Siempre es eficaz y fácil de implementar.
  • Detección de ciclos basada en arrays — transporte los identificadores de los nodos visitados en un array y omita cualquier nodo que ya esté incluido. Se detiene en el primer ciclo.
  • Cláusula CYCLE (PostgreSQL 14+) — sintaxis integrada que automatiza el seguimiento de ciclos mediante las columnas is_cycle y path.
  • statement_timeout — red de seguridad a nivel de base de datos para consultas descontroladas; no sustituye a una lógica adecuada.
  • Combine ambos: el límite de profundidad y la detección de ciclos en producción para obtener la mayor garantía.

Con estas técnicas puede recorrer jerarquías y grafos con confianza, sin arriesgarse a que la base de datos se bloquee.

Preguntas frecuentes

¿La lección «Cómo evitar bucles infinitos» es gratis?

Sí — el texto completo de «Cómo evitar bucles infinitos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de SQL Academy, actualiza a CoddyKit PRO. El curso de SQL Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Cómo evitar bucles infinitos»?

Límites de profundidad y detección de ciclos Practicas SQL Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar SQL Academy?

No se requiere experiencia previa. SQL Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Cómo evitar bucles infinitos»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de SQL Academy?

Sí. Cada lección de SQL Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Cómo funcionan las CTE recursivas
  2. Recorrido de un árbol de categorías
  3. Generación de series y secuencias
  4. Cómo evitar bucles infinitos
← Volver a SQL Academy