miércoles, 25 de junio de 2025

Optimización de Consultas Complejas con CTEs Recursivas en PHP y MySQL

Optimización de Consultas Complejas con CTEs Recursivas en PHP y MySQL

Las consultas complejas en bases de datos pueden convertirse rápidamente en un cuello de botella para el rendimiento de tu aplicación PHP. Una técnica avanzada para mejorar la eficiencia de consultas que implican jerarquías o relaciones recursivas es el uso de Common Table Expressions (CTEs) recursivas. Aunque MySQL 8.0+ soporta CTEs recursivas, a menudo se subestiman en el contexto de la programación PHP. Este post explora cómo implementarlas y optimizar su uso.


<?php

// Función para obtener la jerarquía de una categoría utilizando una CTE recursiva.
function getCategoryHierarchy($pdo, $categoryId) {
    $sql = "
        WITH RECURSIVE CategoryHierarchy AS (
            SELECT id, name, parent_id, 1 AS level
            FROM categories
            WHERE id = :category_id

            UNION ALL

            SELECT c.id, c.name, c.parent_id, ch.level + 1
            FROM categories c
            JOIN CategoryHierarchy ch ON c.id = ch.parent_id
        )
        SELECT id, name, level
        FROM CategoryHierarchy
        ORDER BY level DESC;
    ";

    $stmt = $pdo->prepare($sql);
    $stmt->bindParam(':category_id', $categoryId, PDO::PARAM_INT);
    $stmt->execute();

    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

// Ejemplo de uso:
// Asumiendo que tienes una conexión PDO ya establecida ($pdo).
try {
    $pdo = new PDO("mysql:host=localhost;dbname=mydatabase", "username", "password");
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $categoryId = 5; // ID de la categoría de la que quieres obtener la jerarquía.
    $hierarchy = getCategoryHierarchy($pdo, $categoryId);

    echo "<pre>";
    print_r($hierarchy);
    echo "</pre>";

} catch (PDOException $e) {
    echo "Error: " . $e->getMessage();
}
?>
    

El código anterior define una función `getCategoryHierarchy` que utiliza una CTE recursiva llamada `CategoryHierarchy` para obtener la jerarquía de una categoría específica desde una tabla `categories`. La consulta comienza seleccionando la categoría raíz (definida por `$categoryId`) y luego recursivamente une la tabla consigo misma para obtener sus antepasados. El campo `level` realiza un seguimiento de la profundidad en la jerarquía. Es crucial establecer un límite en la recursión si la base de datos no lo hace automáticamente para evitar loops infinitos.


<?php
// Ejemplo de optimización: limitar la profundidad de la recursión en la consulta.
// (Aunque la CTE en sí no tiene un límite, podemos limitar los resultados en PHP)
function getCategoryHierarchyLimited($pdo, $categoryId, $maxLevel = 5) {
  $hierarchy = getCategoryHierarchy($pdo, $categoryId);
  $filteredHierarchy = array_filter($hierarchy, function($item) use ($maxLevel) {
    return $item['level'] <= $maxLevel;
  });
  return $filteredHierarchy;
}

//Uso de la función optimizada
$limitedHierarchy = getCategoryHierarchyLimited($pdo, $categoryId, 3);
echo "<pre>";
print_r($limitedHierarchy);
echo "</pre>";

?>
    

Si bien MySQL no necesita un límite explícito para la recursión dentro de la CTE (al menos en versiones modernas), es prudente limitar los resultados en el lado de PHP, especialmente si la jerarquía puede ser muy profunda o incluso contener ciclos. El ejemplo `getCategoryHierarchyLimited` muestra como se puede usar `array_filter` para limitar los resultados a una cierta profundidad. Esta optimización, aunque en PHP, previene la visualización de demasiada información que podría sobrecargar al usuario o al sistema.

No hay comentarios:

Publicar un comentario