miércoles, 25 de junio de 2025

Implementando Caching Dinámico de Consultas a Bases de Datos con PHP y TTL Variable

Implementando Caching Dinámico de Consultas a Bases de Datos con PHP y TTL Variable

En aplicaciones web de alto tráfico, el caching de resultados de consultas a la base de datos es crucial para mejorar el rendimiento y reducir la carga del servidor. Este post presenta una técnica para implementar un sistema de caching dinámico con Time-To-Live (TTL) variable, permitiendo ajustar el tiempo de vida del caché según la naturaleza de los datos consultados.


<?php

/**
 * Clase para el caching dinámico de consultas a la base de datos.
 */
class DatabaseCache {

    private $cacheDir;
    private $dbConnection;

    public function __construct(string $cacheDir, PDO $dbConnection) {
        $this->cacheDir = $cacheDir;
        $this->dbConnection = $dbConnection;
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0777, true);
        }
    }

    /**
     * Ejecuta una consulta SQL y retorna los resultados, utilizando caché si es posible.
     *
     * @param string $sql La consulta SQL a ejecutar.
     * @param array $params Parámetros para la consulta (para evitar inyección SQL).
     * @param int $ttl El tiempo de vida del caché en segundos.
     * @return array|false Los resultados de la consulta o false en caso de error.
     */
    public function query(string $sql, array $params = [], int $ttl = 3600) {
        $cacheKey = md5($sql . serialize($params)); // Genera una clave única para el caché.
        $cacheFile = $this->cacheDir . '/' . $cacheKey . '.cache';

        if (file_exists($cacheFile) && (filemtime($cacheFile) + $ttl > time())) {
            // El caché existe y está vigente.
            return unserialize(file_get_contents($cacheFile));
        }

        // El caché no existe o ha expirado, ejecutar la consulta y guardar en caché.
        $stmt = $this->dbConnection->prepare($sql);
        $stmt->execute($params);
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if ($result !== false) {
            file_put_contents($cacheFile, serialize($result));
        }

        return $result;
    }
}

// Ejemplo de uso (requiere una conexión PDO a la base de datos ya establecida):
// $pdo = new PDO("mysql:host=localhost;dbname=mi_base_de_datos", "usuario", "contraseña");
// $cache = new DatabaseCache('/tmp/cache', $pdo);
// $resultados = $cache->query("SELECT * FROM usuarios WHERE activo = :activo", [':activo' => 1], 600); // TTL de 10 minutos.
// print_r($resultados);

El código anterior define una clase `DatabaseCache` que encapsula la lógica de caching. Se utiliza la función `md5` para generar una clave única basada en la consulta SQL y sus parámetros, asegurando que diferentes consultas tengan entradas de caché separadas. La función `filemtime` verifica si el archivo de caché ha expirado según el TTL especificado. La función `serialize` convierte los resultados de la consulta en una cadena para su almacenamiento en el archivo de caché.


<?php
// Ejemplo de uso con TTL dinámico basado en el tipo de datos
// Imaginemos una tabla 'configuracion' donde se guardan configuraciones de la app.
// Las configuraciones que cambian poco (ej: logo) pueden tener un TTL largo,
// mientras que las configuraciones que cambian seguido (ej: timeout) un TTL corto.

function getConfiguracion(string $clave, DatabaseCache $cache) : ?string {
  $ttl = (strpos($clave, 'logo') !== false) ? 86400 : 60; // Logo: 1 día, otros: 1 minuto
  $resultados = $cache->query("SELECT valor FROM configuracion WHERE clave = :clave", [':clave' => $clave], $ttl);

  if ($resultados && count($resultados) > 0) {
    return $resultados[0]['valor'];
  } else {
    return null;
  }
}

//  $pdo = new PDO("mysql:host=localhost;dbname=mi_base_de_datos", "usuario", "contraseña");
//  $cache = new DatabaseCache('/tmp/cache', $pdo);
//  $logo = getConfiguracion('logo_empresa', $cache);
//  $timeout = getConfiguracion('timeout_sesion', $cache);

Este segundo ejemplo muestra cómo se puede implementar un TTL dinámico, variando el tiempo de vida del caché en función de la clave de configuración que se está consultando. Esta flexibilidad permite optimizar el uso del caché y asegurar que los datos se actualicen con la frecuencia adecuada.

No hay comentarios:

Publicar un comentario