2012-07-29 2 views
8

Quando ho eseguito una query sul database e recuperato i risultati in mysqli_result, l'utilizzo della memoria è estremamente ridotto. Tuttavia, quando si prelevano tutte le righe nella query vengono restituite a un array associativo, l'utilizzo della memoria diventa estremamente elevato.PHP: come vengono archiviati i risultati della query in mysqli_result

<?php 
    require_once("../config.php"); //db connection config 
    $db = new mysqli(DB_HOST,DB_USER,DB_PASSWORD,DB_DBASE); 

    $query ="select * from table_name"; 
    if($r = $db->query($query)){ 
    echo "MEMORY USAGE before : ". memory_get_usage()."<br><br>"; 
    $rows = array(); 
    while($row = $r->fetch_assoc()){ 

     $rows[]= $row; 
    } 
    echo "MEMORY USAGE after : ". memory_get_usage()."<br><br>"; 


    //before: 660880 
    //after: 114655768 
    // # of records: around 30 thousands 
?> 

ha senso per me che la memorizzazione di questo molti risultati è molto consumo di memoria, ma mi chiedo solo come mai mysqli_result è così piccolo. Non può essere che i risultati vengano interrogati su dbase ogni volta che viene chiamata fetch_assoc. Allora, dove sono i risultati memorizzati nella memoria.

+1

Ho letto da qualche parte che le funzioni 'mysql_ *' recuperano tutte le righe dei risultati dal server contemporaneamente. Tuttavia PDO (e probabilmente mysqli) recupera ogni riga su richiesta. Quindi, con ogni chiamata da recuperare, userai un po 'di memoria. Ma memorizzi ogni riga in un array, quindi è logico che l'utilizzo della memoria si accumuli. –

+0

Vuoi dire che con ogni chiamata da recuperare, mysqli interrogherà il database per il risultato? – spchuang

+1

Da quanto ho capito, quando chiamate 'query()' MySQL esegue la query e si prepara a restituire tutte le righe dei risultati a PHP. Tuttavia, se mysqli è come PDO (almeno il valore predefinito di PDO), non inizierà a ricevere le righe finché non chiami Fetch. A meno che tu non chiami 'fetchAll()', ogni riga verrà recuperata una alla volta. Ciò significa che l'utilizzo della memoria è perché hai salvato i risultati in un array, non a causa di mysqli. –

risposta

2

C'è una differenza ENORME tra il recupero dei risultati e l'archiviazione di un puntatore a una risorsa.

Se si echo $r; prima della prima chiamata a memory_get_usage();, si renderà conto che è solo un puntatore. Questo è il puntatore al tuo set di risultati. Fino a quando non ottieni i risultati fetch, il set di risultati non verrà effettivamente memorizzato.

Ti suggerisco di eseguire fetchAll() per quello che stai cercando di fare. In questo modo, il metodo 1 accederà a tutti i risultati con prestazioni migliori poiché viene imputato sull'estensione mysqli (libreria C) anziché su un loop in PHP.

Puoi anche utilizzare la funzione risultati gratuiti per cancellare i risultati dalla memoria quando hai finito con loro. Questo è come chiudere un cursore in Java se sei familiare.

+0

Grazie. Questo è molto utile! :) – spchuang

+0

Quindi, perché la risorsa non è effettivamente aggiunta all'utilizzo della memoria?La risorsa utilizza lo spazio di memoria ... O è scritta su disco o qualcosa del genere? –

+0

Facendo eco a '$ r' prima di chiamare fetch, MySQL avrebbe assegnato spazio per i risultati della query, ma non per PHP. PHP assegnerà i risultati al suo spazio di memoria solo quando chiami fetch. –

1

penso che si dovrebbe a questo, invece:

while($row = $r->fetch_assoc()){ 
    //Do whatever you need with the record, then: 
    unset($row); 
} 

Il modo in cui hai postato è la raccolta di una serie enorme di $rows, e l'utilizzo della memoria che riflette.

+0

So cosa intendi e questo è sicuramente l'intenzione originale per fetch_assoc(). Il problema è che sto andando a prendere il risultato e fare qualcosa con esso e passarlo alla vista (in senso MVC) per visualizzare i record. Immagino di poter cambiare la mia implementazione in modo che un record venga passato alla volta. – spchuang

+0

Sarebbe saggio :) – Niloct

+0

Grazie. È un problema perché ho cercato di evitare che la vista potesse comunicare direttamente con i modelli, quindi ho anche un controller nel mezzo per passare i dati. Quello che devo fare è creare un modello di visualizzazione veramente piccolo per visualizzare ogni record ... – spchuang