2012-02-11 18 views
5

Estoy escribiendo un script por lotes y obtengo un error de Allowed memory size of 134217728 bytes exhausted.¿Por qué "Se ha agotado el tamaño de memoria permitido"?

No entiendo por qué la memoria se está llenando. Intenté desarmar la variable $row, pero eso no cambió nada. Aquí está mi código:

// ... (sql connection) 
$result = mysql_query("SELECT * FROM large_table"); 

while ($row = mysql_fetch_array($result)) { 
    echo $row['id'] . PHP_EOL; 
    unset($row); 
} 

(código simplificado)

¿Por qué llenar la memoria, y cómo puedo evitarlo?

Nota: esta es una secuencia de comandos por lotes. Es normal que tenga que manejar datos como ese (pasar por 1 millón de líneas).

Actualización: La falta de memoria ocurre alrededor de la línea 400 000, por lo que tiene que haber algo en el ciclo? Me gustaría evitar tener que implementar la búsqueda si es posible.

+0

No se ve como si se queda sin memoria de ese fragmento de código. ¿Hay alguna otra variable que está creciendo cada iteración? –

+0

¿la consulta de mysql no devolverá realmente la tabla completa -> lo que significa que el resultado se contará en la memoria utilizada? – KillerX

+0

Puede ser una sugerencia tonta, pero es lo único que se me ocurre: ¿quizás podrías intentar vaciar tu buffer de salida? – Martijn

Respuesta

10

Trate de usar http://www.php.net/manual/en/function.mysql-unbuffered-query.php (mysql_unbuffered_query()) para evitar que toda la tabla que se carga en la memoria, pero aún así evitar la paginación.

+0

¡Eso lo hizo! Tu intuición era correcta, y me gusta, responde la raíz del problema. –

+0

por cierto, no entiendo los votos abajo sin explicaciones ... He votado a favor para compensar –

+0

No estoy seguro de que este sea el enfoque correcto, pero +1 ya que responde a la pregunta original :) – halfer

4

Limite su consulta a, por ejemplo, 1k resultados y ejecútelos de nuevo (con el desplazamiento por supuesto) hasta que haya pasado por toda la tabla. Su unset actual no hace ninguna diferencia, ya que $ row se sobrescribe con cada iteración, por lo que puede omitirlo.

$chunk_size = 1000; 
$done = 0; 

$keep_asking_for_data = true; 
do{ 
    $result = mysql_query("SELECT * FROM `large_table` LIMIT {$done}, {$chunk_size}"); 
    $num_rows = mysql_num_rows($result); 
    if($num_rows){ 
     $done += $num_rows; 
     while($row = mysql_fetch_assoc($result)){ 
      echo "{$row['id']}\n"; 
     } 
    } else { 
     $keep_asking_for_data = false; 
    } 
    mysql_free_result($result); 
}while($keep_asking_for_data); 

acaba de compilar en la cabeza, esperemos que funcione = D

+0

Intenté agregar el desarmado para forzar la recolección de la memoria utilizada por la variable, que no está garantizada más (PHP GC). De todos modos, vea el comentario de la otra respuesta y la actualización de la pregunta –

+0

¡Maldición! "Me gustaría evitar tener que implementar la búsqueda si es posible". Esto no estaba allí cuando hice el código: D – PalmTree

+0

¡+1 se ve bien para mí! – halfer

1

Si estás usando MySQL, su página de resultados para que no agota la memoria disponible. MySQL mismo está tomando esta memoria con el conjunto de resultados de su base de datos. Echar un vistazo al siguiente enlace, en particular, la sintaxis LIMIT offset, limit de SELECT:

http://dev.mysql.com/doc/refman/5.0/en/select.html

+0

Eso fue una idea, pero confieso que era demasiado flojo para hacerlo: p. De todos modos, el error ocurre alrededor de la 400 000ª línea (ver actualización de la pregunta) por lo que puede ser algo en el circuito que quizás pueda arreglar. –

+0

Su enfoque, tal como está, * debe * almacenar algunos resultados; eliminar el almacenamiento en búfer para que la paginación sea innecesaria probablemente no sea la manera de hacerlo, imo. De todos modos, debería ser fácil ahora - @PalmTree lo ha hecho por ti :) – halfer

+0

¿Por qué crees que eliminar la paginación no es la mejor forma de hacerlo? –

1

Tuve el mismo problema con una base de datos grande. Me quedé sin memoria, a pesar de haber desconectado la variable $ row en aproximadamente 400,000 registros, pero la consulta sin búferes lo arregló.

Sólo como referencia para los demás (y yo cuando lo hago de nuevo!), Un código de ejemplo consulta sin búfer es:

$sql = "SELECT SEQ, RECTYPE, ROSTERGRP, EMPNM, EMPNUM, DT, RDUTYCAT, ADUTYCAT FROM " . 
     $tblRosters . " ORDER BY EMPNUM,DT"; 
$result = mysql_unbuffered_query($sql, $dbConn); 
$svRow = array(); 
while ($row = mysql_fetch_array($result)) 
    { 
     // your processing code here 
    } 
    // Unset, close db etc. if you are finished goes here. 
Cuestiones relacionadas