Php Quikies: Optimización de Memoria

admin

February 12, 2019

PHP

No Comment

¿Te ha pasado que al correr un script Php te agotas la memoria y te bota un “Allowed Memory Size Exhausted”?

Si es así, hay de dos sopas:
Aumentar la memoria permitida. Esta es la opción rápida y sucia, no es eficiente, no muy recomendable, o mejor dicho, para nada en absoluto.
Eficientizar el uso de memoria de tu script. Esta es la opción eficiente, elegante, la manera a seguir.

Ahora, ¿Cómo eficientizas el uso de memoria en Php? Pues liberándola. Aunque Php cuenta con un garbage collector, es buena práctica no delegarle todo el trabajo, lo que ya no estes ocupando, libéralo, en especial esos arreglos de objetos con muchas propiedades. De hecho, este es el ejemplo perfecto.

Supongámos que estas obteniendo información de una base de datos y vacíandola en archivvos para su rápido acceso fuera de línea o por un servidor FTP, y estas creando una estructura de archivos de este tipo:
Cliente (carpeta)
Año (carpeta)
Mes (este es el archivo, csv digámos)

Pues bien, necesitarás consultas que te traigan los clientes, luego para cada cliente los años que tiene en… digamos ventas, luego para cada cliente y cada año ahora si sus ventas. Cada consulta la almacenas temporalmente en un arreglo.

El algoritmo sería como sigue:

Primero obtienes la totalidad de clientes y lo almacenas en un arreglo.
Recorres ese arreglo y para cada cliente obtienes los años en los que tiene ventas y los almacenas en otro arreglo.
Recorres ese otro arreglo y para cada cliente y año, buscas sus ventas, las almacenas en otro arreglo, exportar ese arreglo a formato CSV y guardas el archivo.

Pues bién, cada arreglo que vas almacenando va consumiendo memoria, bastante, aunque lo vayas reemplazando en cada paso, la memoria se mantiene, ya que lo tienes almacenado mientras realizas la siguiente consulta, obtienes los datos de la consulta en memoria al momento del reemplazo, es decir que estás duplicando información en cada iteración, lo cual lo vuelve exponencial.

Para evitar esto, simplemente libera cada variable volviendola nula en cuanto la dejes de necesitar. El algoritmo en pseudo-código quedaría como esto:

<?php
//  Obtenemos los clientes
$clientes = $db->get(“clientes”);

//  Recorremos los clientes
foreach ($clientes as $cliente) {

	//  Creamos la carpeta
	mkdir($cliente[“cliente_id”]);

	//  Obtenemos los anios
	$sql = “SELECT DISTINCT DATEPART(YEAR, fecha) AS anio FROM ventas WHERE cliente_id = :cliente_id”;
	$anios = $db->query($sql, array(“cliente_id” => $cliente[“cliente_id”]));

	//  Recorremos los anios
	foreach( $anios as $anio) {

		//  Creamos la carpeta
		mkdir($cliente[“cliente_id”].”/”.$anio);

		// Obtenemos los meses
		$sql = “SELECT DISTINCT DATEPART(MONTH, fecha) AS mes FROM ventas WHERE cliente_id = :cliente_id AND DATEPART(YEAR, fecha) = :anio”;
		$meses = $db->query(
			$sql,
			array(
				“cliente_id” => $cliente[“cliente_id”],
				“anio” => $anios[“anio”]
			)
		); // end db query

		//  Recorremos los meses
		foreach ($meses as $mes) {

			// Obtenemos las ventas
			$sql = “SELECT * FROM ventas WHERE cliente_id = :cliente_id AND DATEPART(YEAR, fecha) = :anio AND DATEPART(MONTH, fecha) = : mes”;
			$ventas = $db->query(
				$sql,
				array(
					“cliente_id” => $cliente[“cliente_id”],
					“anio” => $anios[“anio”],
					“mes” => $meses[“mes”]
				)
			); // end db query

			//  Exportamos las ventas
			$csv = to_csv($ventas);

			//  Ya no necesitamos $ventas, lo liberamos
			$ventas = null;

			//  Guardamos el resultado
			file_put_contents($cliente[“cliente_id”].”/”.$anio.”/”.$mes[“mes”].”.csv”, $csv);

			//  Ya no necesitamos $csv, lo liberamos
			$csv = null;
		} // end foreach mes

		//  Ya no necesitamos $meses, lo liberamos.
		$meses = null;

	} // end foreach anios

//  Ya no necesitamos $anios, lo liberamos
$anios = null;

} // end foreach clientes

// Ya no necesitamos $clientes, lo liberamos
$clientes = null;

Ahora nuestro script podrá manejar mejor la memoria y no alcanzaremos el límite, terminando de pronto la tarea con un error.

Hay otras maneras de eficientizar la memoria,, como mandar llamar directamente las funciones con los resultados de otra función, de esta manera nos ahorramos el almacenamiento en variables y no tenemos que liberarlas, así:

file_put_contents(
	$cliente[“cliente_id”].”/”.$anio.”/”.$mes[“mes”].”.csv”,
	to_csv(
		$db->query(
			$sql,
			array(
				“cliente_id” => $cliente[“cliente_id”],
				“anio” => $anios[“anio”],
				“mes” => $meses[“mes”]
			) // end parameters array
		) // end db query
	) // end to_csv
); // end file_put_contents

Aunque de esta manera, para mí, el código se vuelve menos legible. Está en tus manos, es la forma en que más te acomodes para programar. Gracias por leerme y a seguir tirando código :).

Related Posts

Php & gs: Modificar una imágen, guardarla como Pdf y unirla a otro archivo

admin

September 11, 2018

PHP

No Comment

Estaba actualizando mi libro “Correteando la Chuleta“, disponible de forma gratuita aqui, me parece buena idea mandar ediciones personalizadas con un reconocimiento a los lectores, y me di a la tarea de automatizar este proceso. Mi intención es tener un script que mande llamar con solamente el nombre como parámetro y que el resultado sea […]

Read More

Empezar con Php

admin

April 14, 2018

PHP

No Comment

Lo primero que debes saber antes de empezar con Php es que NO es un lenguaje multipropósito, un día si y otro también leo gente quejandose en grupos y foros que para programar para Windows y mobile tienen que aprender otro lenguaje de programación. Bien, si quieres aprender un solo lenguaje de programación – que […]

Read More

Leave a Reply

Your email address will not be published. Required fields are marked *

Busca en el blog aqui

Herramientas Útiles

Suscribete al blog

Recibe en tu correo las últimas publicaciones

Publicidad

Sígueme en Twitter