Foros del Web » Programando para Internet » PHP »

Optimizar y reducir el número de conexiones a la base de datos

Estas en el tema de Optimizar y reducir el número de conexiones a la base de datos en el foro de PHP en Foros del Web. Buenas. Estoy haciendo un proyecto bastante extenso donde sigo un modelo con PDO y MVC donde en algunas de las páginas que cargan superamos las ...
  #1 (permalink)  
Antiguo 11/06/2019, 13:58
Avatar de kahlito
Colaborador
 
Fecha de Ingreso: marzo-2003
Ubicación: En el Estrecho y el mar
Mensajes: 2.928
Antigüedad: 16 años, 8 meses
Puntos: 62
Optimizar y reducir el número de conexiones a la base de datos

Buenas.

Estoy haciendo un proyecto bastante extenso donde sigo un modelo con PDO y MVC donde en algunas de las páginas que cargan superamos las 25 conexiones a la base de datos y por lo tanto da problemas de conexión con el servidor actual que tenemos ya que tiene fijado ese límite de conexiones y me gustaría saber si alguna posibilidad de reducir las consultas las conexiones actuales ya que sino tendremos que cambiar a un servidor dedicado.

Por ejemplo utilizando este módulo en concreto para categorías que cargan en el menú salen 5 conexiones.

cabezote.php

Código PHP:
<!--=====================================
CATEGORÍAS
======================================-->

        <div class="col-xs-12 backColor" id="categorias">

            <?php

                $item 
null;
                
$valor null;

                
$categorias ControladorProductos::ctrMostrarCategorias($item$valor);

                foreach (
$categorias as $key => $value) {

                    echo 
'<div class="col-lg-2 col-md-3 col-sm-4 col-xs-12">
                            
                            <h4>
                                <a href="'
.$url.$value["ruta"].'" class="pixelCategorias">'.$value["categoria"].'</a>
                            </h4>
                            
                            <hr>

                            <ul>'
;

                            
$item "id_categoria";

                            
$valor $value["id"];

                            
$subcategorias ControladorProductos::ctrMostrarSubCategorias($item$valor);
                            
                            foreach (
$subcategorias as $key => $value) {
                                    
                                    echo 
'<li><a href="'.$url.$value["ruta"].'" class="pixelSubCategorias">'.$value["subcategoria"].'</a></li>';
                                }    
                                
                            echo 
'</ul>

                        </div>'
;
                }

            
?>    

        </div>

    </div>
productos-controlador.php

Código PHP:
<?php

class ControladorProductos{

    
/*=============================================
    MOSTRAR CATEGORÍAS
    =============================================*/

    
static public function ctrMostrarCategorias($item$valor){

        
$tabla "categorias";

        
$respuesta ModeloProductos::mdlMostrarCategorias($tabla$item$valor);

        return 
$respuesta;

    }

    
/*=============================================
    MOSTRAR SUBCATEGORÍAS
    =============================================*/

    
static public function ctrMostrarSubCategorias($item$valor){

        
$tabla "subcategorias";

        
$respuesta ModeloProductos::mdlMostrarSubCategorias($tabla$item$valor);

        return 
$respuesta;

    }

?>
modelo-productos.php

Código PHP:
<?php

require_once "conexion.php";

class 
ModeloProductos{

    
/*=============================================
    MOSTRAR CATEGORÍAS
    =============================================*/

    
static public function mdlMostrarCategorias($tabla$item$valor){

        if(
$item != null){

            
$stmt Conexion::conectar()->prepare("SELECT * FROM $tabla WHERE $item = :$item");

            
$stmt -> bindParam(":".$item$valorPDO::PARAM_STR);

            
$stmt -> execute();

            return 
$stmt -> fetch();

        }else{

            
$stmt Conexion::conectar()->prepare("SELECT * FROM $tabla");

            
$stmt -> execute();

            return 
$stmt -> fetchAll();

        }
        
        
$stmt -> close();

        
$stmt null;

    }

    
/*=============================================
    MOSTRAR SUB-CATEGORÍAS
    =============================================*/

    
static public function mdlMostrarSubCategorias($tabla$item$valor){

        
$stmt Conexion::conectar()->prepare("SELECT * FROM $tabla WHERE $item = :$item");

        
$stmt -> bindParam(":".$item$valorPDO::PARAM_STR);

        
$stmt -> execute();

        return 
$stmt -> fetchAll();

        
$stmt -> close();

        
$stmt null;

    }
?>
¿Es posible reducir esta consulta de categorias en el cabezote.php para por ejemplo intentar tener 1 sola conexión o 2 máximo?

En general, ¿hay algún modo global de recudir todas estas conexiones o hacerlo de otra manera? Ya que como comento anteriormente al llevar esta parte a un proyecto mucho más extenso superamos las 25 y hasta 30 conexiones en algunas zonas de la web.

Saludos.
  #2 (permalink)  
Antiguo 11/06/2019, 19:38
 
Fecha de Ingreso: abril-2006
Mensajes: 320
Antigüedad: 13 años, 7 meses
Puntos: 63
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

una pagina les genera 25 conexiones???, entonces el problema esta en que no se esta reusando la conexion previamente abierta, otra forma es que tambien usen CACHE de datos, o si abren una conexion luego de usarse cierrenla
__________________
Mis aportes te ayudaron??, te hicieron ahorrar valiosos tiempo??, si quieres puedes agradecerme con un Gracias o con una donacion
https://paypal.me/pools/c/87BTML2gwr
  #3 (permalink)  
Antiguo 12/06/2019, 12:15
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 9.974
Antigüedad: 11 años, 3 meses
Puntos: 2190
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Muestra el código de tu clase Conexion para ver si ahí es donde está el problema.
__________________
- León, Guanajuato
- GV-Foto
  #4 (permalink)  
Antiguo 12/06/2019, 13:04
Avatar de kahlito
Colaborador
 
Fecha de Ingreso: marzo-2003
Ubicación: En el Estrecho y el mar
Mensajes: 2.928
Antigüedad: 16 años, 8 meses
Puntos: 62
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Hola de nuevo.

En el archivo conexion.php tengo estos datos:


Código PHP:
<?php
 
class Conexion{
 
    public function 
conectar(){
 
        
$link = new PDO("mysql:host=localhost;dbname=nombredb",
                        
"root",
                        
"",
                        array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                              
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
                        );
 
        return 
$link;
 
    }
 
}

Gracias a ambos por vuestras respuestas.
  #5 (permalink)  
Antiguo 12/06/2019, 22:32
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 9.974
Antigüedad: 11 años, 3 meses
Puntos: 2190
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Intenta esto:

Código PHP:
Ver original
  1. // Facilita el manejo extendiendo de PDO
  2. class DBmysql extends PDO {
  3.     // Crea solo una instancia de la clase (patrón Singleton)
  4.     private static $_instance = false;
  5.  
  6.     public static function conectar() {
  7.         // Verificar si no se ha realizado la conexión
  8.         if(self::$_instance === false) {
  9.             // Conectamos a la base de datos
  10.             try {
  11.                 // Verifica que los parámetros son correctos, tomé el código de otra clase
  12.                 self::$_instance = new self(PDO("mysql:host=localhost;dbname=nombredb",
  13.                     "root",
  14.                     "",
  15.                     array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  16.                         PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
  17.                 );
  18.             } catch (PDOException $e) {
  19.                 // Hay que elaborar mejor el manejo de errores, esto solo es ejemplo
  20.                 die('No se puede establecer una conexión a base de datos.');
  21.             }
  22.         }
  23.         return self::$_instance;
  24.     }
  25. }
__________________
- León, Guanajuato
- GV-Foto

Última edición por Triby; 12/06/2019 a las 22:44
  #6 (permalink)  
Antiguo 16/06/2019, 19:27
Avatar de kahlito
Colaborador
 
Fecha de Ingreso: marzo-2003
Ubicación: En el Estrecho y el mar
Mensajes: 2.928
Antigüedad: 16 años, 8 meses
Puntos: 62
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Hola Triby

He realizado solo un pequeño cambio en tu código y parece que va perfecto:

Código PHP:
Ver original
  1. // // Facilita el manejo extendiendo de PDO
  2. class DBmysql extends PDO {
  3. //class DBmysql extends Conexion {
  4.     // Crea solo una instancia de la clase (patrón Singleton)
  5.     private static $_instance = false;
  6.  
  7.     public static function conectar() {
  8.         // Verificar si no se ha realizado la conexión
  9.         if(self::$_instance === false) {
  10.             // Conectamos a la base de datos
  11.             try {
  12.                 // Verifica que los parámetros son correctos, tomé el código de otra clase
  13.                 self::$_instance = new PDO("mysql:host=localhost;dbname=nombrebd",
  14.                         "root",
  15.                         "",
  16.                         array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  17.                               PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
  18.                         );
  19.  
  20.                 //Intento ver en el código fuente las actuales conexiones a la BD.
  21.                 echo "Acabo de conectarme FW";
  22.  
  23.             } catch (PDOException $e) {
  24.                 // Hay que elaborar mejor el manejo de errores, esto solo es ejemplo
  25.                 die('No se puede establecer una conexión a base de datos.');
  26.             }
  27.         }
  28.         return self::$_instance;
  29.     }
  30. }

Luego por ejemplo en el modelo de subcategorías solo cambio Conexion por DBmysql y listo:

Código PHP:
Ver original
  1. /*=============================================
  2. MOSTRAR SUB-CATEGORÍAS SINGLETON
  3. =============================================*/
  4.  
  5.     static public function mdlMostrarSubCategorias($tabla, $item, $valor){
  6.  
  7.                 $stmt = DBmysql::conectar()->prepare("SELECT * FROM $tabla WHERE $item = :$item");
  8.  
  9.         $stmt -> bindParam(":".$item, $valor, PDO::PARAM_STR);
  10.  
  11.         $stmt -> execute();
  12.  
  13.         return $stmt -> fetchAll();    
  14.  
  15.         $stmt -> close();
  16.  
  17.         $stmt = null;
  18.  
  19.     }
Por lo que veo ahora al aplicar este nuevo método reduce en gran cantidad el número de conexiones a la base de datos, pero no estoy seguro del todo si lo estoy haciendo de la manera correcta tanto en ver cuantas conexiones hago por página y también en como lo estoy aplicando al código actual.

¿Estoy en lo correcto como lo estoy haciendo ahora?

He visto incluso que si por ejemplo también añado $stmt = DBmysql::conectar() a otros funciones dentro del mismo modelo (productos-modelo.php) por ejemplo en categorías o en listar productos o cualquier otra zona que en total solo aparece 1 conexión.

Por ejemplo aquí aplico el mismo cambio para categorías.

Código PHP:
Ver original
  1. /*=============================================
  2.     MOSTRAR CATEGORÍAS
  3.     =============================================*/
  4.  
  5.     static public function mdlMostrarCategorias($tabla, $item, $valor){
  6.  
  7.         if($item != null){          
  8.  
  9.             $stmt =  DBmysql::conectar()->prepare("SELECT * FROM $tabla WHERE $item = :$item");          
  10.  
  11.             $stmt -> bindParam(":".$item, $valor, PDO::PARAM_STR);
  12.  
  13.             $stmt -> execute();
  14.  
  15.             return $stmt -> fetch();        
  16.  
  17.  
  18.         }else{            
  19.  
  20.             $stmt =  DBmysql::conectar()->prepare("SELECT * FROM $tabla");
  21.  
  22.             $stmt -> execute();
  23.  
  24.             return $stmt -> fetchAll();        
  25.  
  26.         }
  27.        
  28.         $stmt -> close();
  29.  
  30.         $stmt = null;
  31.  
  32.     }

Con este cambio entonces aunque me conecto ya más de una vez en total me da 1 conexión.

Me pregunto entonces que si también cambio todas las anteriores consultas de $stmt = Conexion:: al nuevo $stmt = DBmysql:: , ¿sería posible dejar solo 1 conexión por página en total o es mejor aplicar dicha esta nueva opción solo en algunas zonas concretas del proyecto que generen varias conexiones a la vez como por ejemplo sería subcategorías, listado de productos etc etc? Es decir o meter en todas $stmt = DBmysql:: o solo cambiarla en zonas que generen varias consultas a la base de datos y en el resto mantener la anterior de $stmt = Conexion::

Espero no haber liado mucho la pregunta...

Por cierto, supongo que conoces este ejemplo, comentar que también me recomendaron hacer algo parecido siguiendo este enlace:

https://gist.github.com/ftonato/2973...a48804dcdb71dd

Sin embargo creo que tu ejemplo se adapta y me facilita más el trabajo al proyecto actual.

Gracias por tu gran ayuda.

Saludos.
  #7 (permalink)  
Antiguo 17/06/2019, 14:38
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 9.974
Antigüedad: 11 años, 3 meses
Puntos: 2190
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Resultaría más fácil si cambias el nombre de la clase DBmysql remplazando la que tienes actualmente, así no modificas todo el código que ya tienes.

Y, sí, la idea es que cada petición genere solo una conexión a base de datos, sin importar la cantidad de consultas a realizar.

No conocía el ejemplo que mencionas, tiene algunas otras características, pero finalmente hará lo mismo.
__________________
- León, Guanajuato
- GV-Foto
  #8 (permalink)  
Antiguo 17/06/2019, 16:44
Avatar de kahlito
Colaborador
 
Fecha de Ingreso: marzo-2003
Ubicación: En el Estrecho y el mar
Mensajes: 2.928
Antigüedad: 16 años, 8 meses
Puntos: 62
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Ok, supongo entonces que ahora quedaría algo así como este ejemplo:

conexion.php

Código PHP:
Ver original
  1. // Nueva conexión singleton
  2. class Conexion {
  3.  
  4.     // Crea solo una instancia de la clase (patrón Singleton)
  5.     private static $_instance = false;
  6.  
  7.     public static function conectar() {
  8.  
  9.         // Verificar si no se ha realizado la conexión
  10.         if(self::$_instance === false) {
  11.             // Conectamos a la base de datos
  12.             try {
  13.                 // Verifico que los parámetros sea correctos.
  14.                 self::$_instance = new PDO("mysql:host=localhost;dbname=nombrebd",
  15.                         "root",
  16.                         "",
  17.                         array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  18.                               PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")
  19.                         );
  20.                
  21.                 //Intento ver en el código fuente las actuales conexiones a la BD.
  22.                 echo "Acabo de conectarme FW final";
  23.  
  24.             } catch (PDOException $e) {
  25.                 //Manejo de errores, esto solo es ejempl.o
  26.                 die('No se puede establecer una conexión a base de datos.');
  27.             }
  28.         }
  29.  
  30.         return self::$_instance;
  31.        
  32.     }
  33.  
  34. }

productos-modelo.php

Código PHP:
Ver original
  1. <?php
  2.  
  3. require_once "conexion.php";
  4.  
  5. class ModeloProductos{
  6.  
  7.     /*=============================================
  8.     MOSTRAR CATEGORÍAS
  9.     =============================================*/
  10.  
  11.     static public function mdlMostrarCategorias($tabla, $item, $valor){
  12.  
  13.         if($item != null){
  14.  
  15.             $stmt = Conexion::conectar()->prepare("SELECT * FROM $tabla WHERE $item = :$item");        
  16.  
  17.             $stmt -> bindParam(":".$item, $valor, PDO::PARAM_STR);
  18.  
  19.             $stmt -> execute();
  20.  
  21.             return $stmt -> fetch();
  22.  
  23.         }else{
  24.  
  25.             $stmt = Conexion::conectar()->prepare("SELECT * FROM $tabla");         
  26.  
  27.             $stmt -> execute();
  28.  
  29.             return $stmt -> fetchAll();        
  30.  
  31.         }
  32.        
  33.         $stmt -> close();
  34.  
  35.         $stmt = null;
  36.  
  37.     }
  38.  
  39. /*=============================================
  40. MOSTRAR SUB-CATEGORÍAS
  41. =============================================*/
  42.  
  43.     static public function mdlMostrarSubCategorias($tabla, $item, $valor){ 
  44.  
  45.         $stmt = Conexion::conectar()->prepare("SELECT * FROM $tabla WHERE $item = :$item");
  46.  
  47.         $stmt -> bindParam(":".$item, $valor, PDO::PARAM_STR);
  48.  
  49.         $stmt -> execute();
  50.  
  51.         return $stmt -> fetchAll();    
  52.  
  53.         $stmt -> close();
  54.  
  55.         $stmt = null;
  56.  
  57.     }

Ahora parece que va todo perfectamente e incluso que solo aparece en total una vez "Acabo de conectarme FW final" como aviso de conectado.

También me han sugerido otra opción que aun no he logrado adaptar bien a este método que sería con PDOStatement::closeCursorphp

¿Alguna otra sugerencia o mejora o ya con esto estaría todo arreglado?

Gracias de nuevo.

Saludos.
  #9 (permalink)  
Antiguo 17/06/2019, 22:19
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 9.974
Antigüedad: 11 años, 3 meses
Puntos: 2190
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Con esta clase ya no vas a tener el problema de crear múltiples conexiones en una sola petición.

En cuanto a closeCursor, tú mismo podrás decirnos si lo requieres o no, simplemente leyendo el manual:

Cita:
Este método es útil para los controladores de bases de datos que no admiten la ejecución de un objeto PDOStatement cuando otro objeto PDOStatement previamente ejecutado aún le restan filas por obtener. Si su controlador de bases de datos tiene esta limitación, el problema podría manifestarse en un error de "fuera de sencuencia".
Has experimentado errores en este sentido? entonces hay que usarlo.
__________________
- León, Guanajuato
- GV-Foto
  #10 (permalink)  
Antiguo 28/06/2019, 16:23
Avatar de kahlito
Colaborador
 
Fecha de Ingreso: marzo-2003
Ubicación: En el Estrecho y el mar
Mensajes: 2.928
Antigüedad: 16 años, 8 meses
Puntos: 62
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Cita:
Iniciado por Triby Ver Mensaje
Con esta clase ya no vas a tener el problema de crear múltiples conexiones en una sola petición.
Hola de nuevo Triby.

Por ahora he seguido probando y como comentaba en mi último post va todo perfecto.

Cita:
Iniciado por Triby Ver Mensaje
En cuanto a closeCursor, tú mismo podrás decirnos si lo requieres o no, simplemente leyendo el manual:



Has experimentado errores en este sentido? entonces hay que usarlo.


La verdad es que por ahora no he tenido errores, así que lo dejo tal y como está ahora.

De nuevo gracias.

Saludos.
  #11 (permalink)  
Antiguo 01/07/2019, 22:44
 
Fecha de Ingreso: octubre-2007
Mensajes: 272
Antigüedad: 12 años, 1 mes
Puntos: 5
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Hola kahlito, el forista Triby te acaba de introducir el patrón Singleton en tu clase Conexion, que te garantizará tener siempre una conexion, no importe las veces que la llames en una corrida, muy bien por su parte.
Imagino que hayas publicado sentencias SQL sencillas para resolver el mayor problema que tenías en tu código y que evidentemente estaba agotando los recursos de tu servidor.

Te recomiendo no hacer un uso extensivo de sentencias sql del tipo
Código:
Select * FROM ....
; es más, si en determinado momento solamente necesitaras digamos 3 campos de una tabla que contiene unos 15 columnas, pues aplica
Código:
SELECT campo1, campo2, campo3 FROM .....
, con esto le estarías ahorrando recursos de procesamiento a tu servidor.
De igual manera cuando necesites hacer un conteo de registro, no emplear
Código:
SELECT COUNT(*) FROM ...
, también atenta contra el rendimiento de tus consultas.
Bueno algo mejor, no voy a citar lo que está de sobra en internet, te refiero al siguiente artículo: https://www.solvetic.com/tutoriales/...es-para-mysql/, espero te sea de ayuda.
Saludos
  #12 (permalink)  
Antiguo 02/07/2019, 04:18
Avatar de kahlito
Colaborador
 
Fecha de Ingreso: marzo-2003
Ubicación: En el Estrecho y el mar
Mensajes: 2.928
Antigüedad: 16 años, 8 meses
Puntos: 62
Respuesta: Optimizar y reducir el número de conexiones a la base de datos

Hola X_fran

Aunque algo había leido sobre esas consultas e incluso en algunas de ellas las tengo optimizadas tu enlace y explicación me sirve de mucho ya que también hay nuevos puntos que debo mejorar.

Muchas gracias por tu ayuda.

Saludos.



La zona horaria es GMT -6. Ahora son las 04:05.