2010-03-03 10 views
6

Estoy tratando de crear un mapa del sitio XML usando CakePHP, desde una tabla que tiene más de 50,000 registros en este momento, cada registro equivalente a un URI en el mapa del sitio. Ahora el problema que estoy enfrentando es CakePHP me está quedando sin memoria mientras que la generación que, por dos razones:¿Recomendación de CakePHP para iterar una tabla enorme y generar un mapa del sitio?

  1. find('all') Una es la construcción de una enorme matriz asociativa de todo el conjunto de 50.000 URI.
  2. Como no deseo imprimir HTML desde el controlador, transfiero la matriz asociativa que contiene el URI, la prioridad, la frecuencia de cambio, etc., a la vista con una llamada $this->set(), que de nuevo es enorme y contiene 50,000 índices.

¿Es posible en absoluto hacer esto siguiendo las pautas de MVC y CakePHP?

Respuesta

2

¿Estás seguro de que tienes que quedarte sin memoria en 50,000 registros? Incluso si una fila tiene 1K de tamaño (bastante grande), ¿tendría que tratar con ~ 50 MB de datos? Mi P1 tenía suficiente memoria RAM para manejar eso. Establezca memory_limit en php.ini más alto que el predeterminado. (Considere también ajustar max_execution_time).

Por otro lado, si considera que el conjunto de datos es demasiado extenso y lo procesa como demasiado intensivo en recursos, no debe publicar esa página dinámicamente, es el cebo DDoS perfecto. (Al menos lo almacenaría en caché.) Podría programar una tarea cron para volver a generar la página cada X horas con un script del lado del servidor libre de la penalización MVC de servir todos los datos a la vez a la vista, podría funcionar en las filas secuencialmente.

+0

El mapa del sitio funciona absolutamente bien en mi cuadro de desarrollo local. Una vez que despliegue en mi alojamiento compartido donde tengo memoria muy limitada, explota. Esto es exactamente en lo que estaba pensando, solo quería volver a verificarlo y asegurarme de seguir así porque no me quedan opciones de CakePHP/MVC. ¡Gracias! –

1

Ha intentado unbindModel (si tiene relaciones) ...

Cada vez que tengo que hacer enormes consultas en cakephp sólo tiene que utilizar las funciones de MySQL "normales" como mysql_query, etc. mysql_fetch_assoc mucho más rápido, y sin falta de memoria ...

+0

Esta es una tabla única SELECCIONAR. Parece que MySQL de la vieja escuela es la forma eficiente y única de ir, pero ya estoy muy lejos de CakePHP. Y todavía tengo el problema de cómo representar la matriz asociada calculada. –

3

Tuve un problema similar esta semana y tropecé con el Containable Comportamiento. Esto le permite reducir cualquier consulta relacionada con las relaciones (si tiene alguna).

La mejor solución sería usar programáticamente LIMIT and OFFSET, y recorrer los pequeños fragmentos del conjunto de registros a la vez. Esto le ahorra rellenar 50K registros en la memoria a la vez.

+0

Gracias por la respuesta. No tengo ninguna tabla relacionada y la consulta es más o menos una simple operación 'SELECT'. Disparar múltiples consultas es algo que quería evitar. Además, incluso si lo hago, ¿cómo puedo transferir los datos a la vista? –

+0

¿Visualizaría todos los 50k registros en la misma vista? De lo contrario, la mayoría de los patrones de paginación funcionan bien con la consulta de límite/compensación. Si tiene que mostrarlos todos a la vez, tal vez profundizar en su php.ini (si tiene acceso de administrador a su servidor) y cambiar memory_limit a un valor mayor. Eso podría solucionar tus problemas de memoria con un find ('todo). Si su tabla tiene muchos campos, use el valor de 'campos' para restringir lo que es necesario (como se menciona en otro comentario). – bojo

2

find ('todo') es demasiado codicioso, tendrás que ser más específico si no quieres quedarte sin memoria.

Como se indicó anteriormente, use el comportamiento Containable. Si sólo necesita los resultados de su mesa, (sin tablas asociado) y sólo por un par de campos, una consulta más explícita como este debería ser mejor:

$results = $this->YourModel->find('all', array(
    'contain' => false, 
    'fields' => array('YourModel.name', 'YourModel.url') 
); 

también se debe considerar la adición de un mecanismo de caché html (CakePHP tiene un built-in o usa el suggested by Matt Curry).

Por supuesto, será una versión en caché, y no estará perfectamente actualizada en su lista. Si desea más control, siempre puede guardar el resultado en Cake Cache (usando Cache::write), utilizando las devoluciones de llamada afterSave/afterDelete de su modelo para actualizar el valor en caché y recrear el archivo xml en caché desde aquí.

+0

Específicamente, mira el argumento "fields" para encontrar(). –

4

Sé que esta pregunta es antigua, pero para las consultas realmente grandes todavía no hay una buena solución, creo.

Para iterar a través de un enorme conjunto de resultados, puede utilizar métodos DboSource.

En primer lugar obtener el DBO

$dbo = $this->Model->getDataSource(); 

Construir la consulta

$sql = $dbo->buildStatement($options); 

A continuación, ejecutar la instrucción e iterar a través de los resultados

if ($dbo->execute($sql)) 
{ 
    while ($dbo->hasResult() && $row = $dbo->fetchResult()) { 
     // $row is an array with same structure like find('first') 
    } 
} 
+0

A partir de CakePHP 2.4.4, '' dbo-> buildStatement' requiere dos parámetros. Además, '' dbo-> buildStatement' solo devuelve un SQL inválido sin nombre de tabla. Después de indagar en la fuente, utilicé '$ this-> generateAssociationQuery ($ model, null, null, null, null, $ queryData, false, $ null);' en su lugar – VCD

Cuestiones relacionadas