2010-03-10 15 views
32

Ho alcune domande sull'utilizzo di MySQLi, query e gestione della memoria correlata. Il codice qui è solo per chiarire le mie domande, in modo da non discarica su di esso per il controllo degli errori, ecc so che deve essere fatto :)Risultati query MySQLi: approccio migliore, chiudi, libero, entrambi?

Supponiamo che io abbia qualcosa di simile:

@ $db = new mysqli($dbhost, $un, $ps, $dbname); 
$query = "SELECT field1, field2 ". 
     "FROM table1 ". 
     "WHERE field1={$some_value}"; 
$results = $db->query($query); 

while ($result = $results->fetch_object()) { 
    // Do something with the results 
} 

$query = "SELECT field1, field2 ". 
     "FROM table2 ". 
     "WHERE field1={$some_value2}"; 
// question 1 
$results = $db->query($query); 

while ($result = $results->fetch_object()) { 
    // Do something with the second set of results 
} 

// Tidy up, question 2 
if ($results) { 
    $results->free(); 
} 
if ($db) { 
    $db->close(); 
} 

// Question 3, a general one 

Quindi, sulla base dei commenti nel codice sopra, qui sono le mie domande:

  1. Quando assegno i risultati della seconda query per $results, cosa succede alla memoria associata con i risultati precedenti? Devo liberare quel risultato prima di assegnare quello nuovo?

  2. Correlato a 1, quando pulisco alla fine, è sufficiente pulire solo gli ultimi risultati?

  3. Quando provo a ripulire un risultato, dovrei liberarlo come sopra, dovrei chiuderlo o entrambi?

Chiedo domanda 3 in quanto la documentazione PHP per mysqli::query ha un esempio che utilizza vicino, anche se vicino non fa parte della mysqli_result (vedi esempio 1 in mysqli::query). E al contrario, il mio normale testo di riferimento PHP utilizza free (PHP e MySQL Web Development, Quarta Edizione, Welling e Thomson).

+3

Conoscete il momento in cui sono passati anni da quando avete lavorato a un progetto e decidete di verificare StackOverflow per una risposta a una domanda solo per scoprire che avete già chiesto e ha risposto a quella domanda anni fa ...? Uh ... Devo essere vecchio :) Grazie ancora per le ottime risposte qui sotto. –

risposta

48

Quando assegno i risultati della seconda query a $results, ciò che accade alla memoria associata con i risultati precedenti ?

Quando si esegue questo:

$results = $db->query($query); 

Se c'era qualcosa in $results prima, questo vecchio contenuto non è possibile accedere più, in quanto non v'è alcun riferimento a sinistra per esso.

In tal caso, PHP segnerà il vecchio contenuto della variabile come "non più necessari" - e verranno rimossi dalla memoria quando il PHP ha bisogno di un po 'di memoria.

Questo, almeno, è vero per le variabili PHP generiche; nel caso di risultati di una query SQL, tuttavia, alcuni dati potrebbero essere conservati in memoria a livello di driver - su cui PHP non ha molto controllo.


Dovrei essere liberare gli risultato prima assegnare il nuovo?

non lo faccio mai - ma, citando la pagina di manuale di mysqli_result::free:

Nota: Si dovrebbe sempre libera la tua risultato con mysqli_free_result(), quando l'oggetto risultato non è necessario più

probabilmente non ha importanza per un piccolo script ... e l'unico modo per essere sicuri sarebbe quello di testare, utilizzando memory_get_usage prima e dopo la chiamata che meto d, per vedere se c'è una differenza o no.


correlati a 1, quando lo faccio ripulire alla fine, sta pulendo solo negli ultimi risultati abbastanza?

Quando gli script fine:

  • La connessione al database verrà chiuso - il che significa qualsiasi memoria che potrebbe essere utilizzato da parte del pilota non deve essere liberato
  • Tutte le variabili utilizzate dal PHP lo script verrà distrutto, il che significa che la memoria che stavano usando dovrebbe essere liberata.

Quindi, alla fine dello script, probabilmente non è necessario liberare il set di risultati.


Quando cerco di ripulire un risultato, dovrei essere liberandola come sopra, dovrei essere chiuderlo, o entrambi?

Se si chiude la connessione al database (utilizzando mysqli::close come te proposto), questa si disconnette si dal database.

Il che significa che dovrai riconnetterti se vuoi fare un'altra query! Il che non va bene a tutti (richiede un certo tempo, risorse, ...)

In generale, non vorrei chiudere la connessione al database fino a che non sono realmente sicuro che non avrò più bisogno - il che significa che non mi disconnetterei prima della fine dello script.

e come "fine dello script" significa "la connessione verrà chiusa", anche se non si specifica che; Non chiudo quasi mai la connessione da solo.

+3

Wow! Questa è una risposta eccellente e molto ben scritta e informativa. Esattamente quello che stavo cercando. Grazie! Immagino che tutto sommato sia eccessivamente preoccupato per una lingua che gestisce la raccolta dei rifiuti. Grazie ancora! –

+0

Prego :-) ;;; beh, potresti essere sincero riguardo alla garbage collection - ma non dimenticare che l'uso primario di PHP è per script che raramente durano più di un paio di secondi - il che significa che anche se c'è qualche perdita di memoria, generalmente non lo è così male. –

+0

Buon punto. Sono ancora un "debuttante" nel mondo dello sviluppo web, quindi forse il mio passato di utilizzo di linguaggi compilati più vecchi mi ha sproporzionatamente preoccupato quando si tratta di gestione della memoria! :) –

-3

Il modo generale di PHP non è quello di chiudere alcuna risorsa aperta. Tutto verrà automaticamente chiuso alla fine dello script. Il solo caso in cui è necessario avere cura della chiusura manuale è se si dispone di codice lungo pesante per eseguire, che non è molto comune per PHP.

+2

Grazie, è semplice. Tuttavia, perché la lingua include gratuitamente come parte di mysqli_result? È una cosa legacy? –

13

Le risposte già fornite sono buone, ma volevo aggiungere un punto e chiarirne un altro.

In primo luogo, il chiarimento. Per quanto riguarda l'uso del metodo close(), è importante notare che l'OP stava facendo riferimento al metodo close() della classe mysqli_result, non alla classe mysqli.Nella classe result, il metodo close() è semplicemente un alias del metodo free(), come mostrato nello documentation, mentre nella classe mysqli chiude la connessione. Quindi, va bene usare close() sul risultato al posto di free() se lo si desidera.

In secondo luogo, il punto aggiuntivo. Come è stato già sottolineato, il modello di esecuzione di PHP significa che alla fine tutto verrà ripulito e quindi non è necessario preoccuparsi di rilasciare la memoria. Tuttavia, se stai allocando molti oggetti risultato o se stai allocando oggetti risultato particolarmente grandi (ad esempio, recuperando una grande quantità di dati), probabilmente dovresti liberare la memoria quando hai finito per prevenire ulteriori problemi lungo il percorso dell'esecuzione. Ciò diventa particolarmente importante quando l'applicazione inizia a ricevere più traffico, in cui la quantità totale di memoria accumulata nelle sessioni può diventare rapidamente significativa.

0

Raramente come sono, a mio parere le perdite di memoria sono un incubo da trovare e correggere. Esco dal mio modo di evitarli. Qui di seguito è il modello che uso, in base al codice da Lei forniti:

$db = NULL; 
try { 
    $dbPool = "p:$dbhost"; // question 3: use pooling 
    $db = new mysqli($dbPool, $un, $ps, $dbname); 
    if ($db->connect_errno) { 
     throw new Exception('' . $db->connect_error . ' ' . $db->connect_errno 
       . "\n" . $un . '@' . $dbhost . ' ' . $dbname); 
     // NOTE: It's commonly considered a security 
     // risk to output connection information e.g. 
     // host, user and database names. 
    } 

    $query = "SELECT field1, field2 ". 
      "FROM table1 ". 
      "WHERE field1={$some_value}"; 

    $results = NULL; 
    try { 

     if (!$results = $db->query($query)) { 
      throw new Exception($db->error . " " . $db->errno 
        . "\n" . $query); 
      // NOTE: It's commonly considered a security 
      // risk to output SQL ($query). 
     } 
     while ($result = $results->fetch_object()) { 
      // Do something with the results 
     } 

    } catch (Exception $ex) { 
     // log, report, or otherwise handle the error 
    } 
    if ($results) { 
     $results->free(); // question 1: why risk it? 
    } 

    $query = "SELECT field1, field2 ". 
      "FROM table2 ". 
      "WHERE field1={$some_value2}"; 

    $results = NULL; 
    try { 

     if (!$results = $db->query($query)) { 
      throw new Exception($db->error . " " . $db->errno 
        . "\n" . $query); 
      // NOTE: It's commonly considered a security 
      // risk to output SQL ($query). 
     }    
     while ($result = $results->fetch_object()) { 
      // Do something with the second set of results 
     } 

    } catch (Exception $ex) { 
     // log, report, or otherwise handle the error 
    } 
    if ($results) { 
     $results->free(); // question 2: again, why risk it? 
    } 

} catch (Exception $ex) { 
    // log, report, or otherwise handle the error 
} 
if ($db) { 
    $db->close(); 
} 

A mio parere, il pool di connessioni aumenta le probabilità di una perdita di memoria, ma secondo il manuale, le librerie il pool di connessioni fare un sacco di pulizia per te automaticamente:

La connessione persistente dell'estensione mysqli tuttavia fornisce il codice di gestione della pulizia incorporato . La pulitura effettuata da mysqli comprende:

rollback transazioni attive

Chiudere ed eliminare tabelle temporanee

tavoli Sblocca

variabili di reimpostare la sessione

Chiudi istruzioni preparate (accade sempre con PHP

Close handler

serrature Stampa acquisiti con GET_LOCK()

Questo assicura che le connessioni persistenti sono in uno stato pulito su ritorno dal pool di connessioni, prima che il processo client li utilizza.

fonte:http://php.net/manual/en/mysqli.persistconns.php

Sono anche d'accordo con Pascal MARTIN che è una buona idea quella di aprire il collegamento all'inizio del vostro script e chiuderlo alla fine. Penso che la messa in comune delle connessioni lo renda meno importante, ma comunque una buona idea.

Problemi correlati