2012-02-11 21 views
5

Sto scrivendo uno script batch e ottengo un errore Allowed memory size of 134217728 bytes exhausted.Perché "La dimensione della memoria consentita è esaurita"?

Non capisco perché la memoria si sta riempiendo. Ho provato a disattivare la variabile $row, ma questo non ha cambiato nulla. Ecco il mio codice:

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

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

(codice semplificato)

Perché la memoria riempire, e come posso evitarlo?

Nota: questo è uno script batch. È normale che io gestisca dati del genere (oltre 1 milione di righe).

Aggiornamento: la memoria esaurita si verifica intorno alla 400 000a linea, quindi deve essere qualcosa nel ciclo? Mi piacerebbe evitare di dover implementare il paging, se possibile.

+0

E non sembra che si dovrebbe esaurire la memoria da quel frammento di codice. C'è qualche altra variabile che sta crescendo ogni iterazione? –

+0

la query mysql non restituirà effettivamente l'intera tabella -> significa che il risultato verrà conteggiato nella memoria utilizzata? – KillerX

+0

Potrebbe essere un suggerimento stupido, ma è l'unica cosa che posso pensare: forse potresti provare a svuotare il buffer di output? – Martijn

risposta

10

Provare a utilizzare http://www.php.net/manual/en/function.mysql-unbuffered-query.php (mysql_unbuffered_query()) per evitare che l'intera tabella viene caricata in memoria, ma comunque evitando l'impaginazione.

+0

Questo l'ha fatto! La tua intuizione era giusta, e mi piace che risponda alla radice del problema. –

+0

btw Non capisco i downvotes senza spiegazioni ... Ho upvoted per compensare –

+0

Non sono sicuro che questo sia l'approccio giusto, ma +1 poiché risponde alla domanda originale :) – halfer

4

Limita la query ad esempio risultati 1k ed eseguila nuovamente (con l'offset del corso) finché non hai completato tutta la tabella. Il tuo non impostato corrente non fa alcuna differenza, poiché la riga $ viene sovrascritta a ogni iterazione, quindi puoi saltarla.

$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); 

appena compilato sulla mia testa, spero che funziona = D

+0

Ho provato ad aggiungere il unset per forzare la raccolta della memoria utilizzata dalla variabile, che non è garantita altro (PHP GC). Ad ogni modo, vedi il commento all'altra risposta e la domanda aggiornamento –

+0

Dannazione! "Mi piacerebbe evitare di dover implementare il paging, se possibile." Questo non c'era quando ho creato il codice: D – PalmTree

+0

+1 mi sembra buono! – halfer

1

Se stai usando MySQL, pagina i risultati in modo da non esaurire la memoria disponibile. MySQL stesso sta prendendo questa memoria con il tuo set di risultati del database. Date un'occhiata al seguente link, in particolare la LIMIT offset, limit sintassi del SELECT:

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

+0

Questa era un'idea ma confesso che ero troppo pigro per farlo: p. Ad ogni modo, l'errore si verifica intorno alla 400 000 ° linea (vedi aggiornamento della domanda) quindi potrebbe essere qualcosa nel ciclo che forse posso risolvere? –

+0

Il tuo approccio così com'è * dovrebbe * bufferizzare alcuni risultati - rimuovere il buffering in modo che il paging non sia necessario non è probabilmente il modo di farlo, imo. Comunque dovrebbe essere facile ora - @PalmTree lo ha fatto per voi :) – halfer

+0

Perché pensi che la rimozione del paging non sia il modo migliore per farlo? –

1

Ho avuto lo stesso problema con un database di grandi dimensioni. Ho esaurito la memoria, nonostante avessi disattivato la variabile $ row a circa 400.000 record, ma la query unbuffered l'ha risolta.

Solo per riferimento per gli altri (me e quando lo faccio di nuovo!), Qualche esempio di codice di query senza buffer è:

$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. 
Problemi correlati