Mysql
 sql >> Database >  >> RDS >> Mysql

Cause dell'errore MySQL 2014 Impossibile eseguire query mentre altre query senza buffer sono attive

Il protocollo client MySQL non consente che più di una query sia "in corso". Cioè, hai eseguito una query e hai recuperato alcuni dei risultati, ma non tutti, quindi provi a eseguire una seconda query. Se la prima query ha ancora righe da restituire, la seconda query riceve un errore.

Le librerie client aggirano questo problema recuperando tutto le righe della prima query in modo implicito al primo recupero, quindi i successivi recuperi semplicemente ripetono i risultati memorizzati nella cache interna. Questo dà loro l'opportunità di chiudere il cursore (per quanto riguarda il server MySQL). Questa è la "query nel buffer". Funziona allo stesso modo dell'utilizzo di fetchAll(), in quanto entrambi i casi devono allocare memoria sufficiente nel client PHP per contenere l'intero set di risultati.

La differenza è che una query nel buffer conserva il risultato nella libreria del client MySQL, quindi PHP non può accedere alle righe finché non si recupera () ogni riga in sequenza. Mentre fetchAll() popola immediatamente un array PHP per tutti i risultati, consentendoti di accedere a qualsiasi riga casuale.

Il motivo principale non usare fetchAll() è che un risultato potrebbe essere troppo grande per adattarsi al tuo memory_limit PHP. Ma sembra che i risultati della tua query abbiano comunque solo una riga, quindi non dovrebbe essere un problema.

Puoi chiudereCursor() per "abbandonare" un risultato prima di aver recuperato l'ultima riga. Il server MySQL viene informato che può scartare quel risultato sul lato server e quindi puoi eseguire un'altra query. Non dovresti chiudereCursor() finché non hai finito di recuperare un determinato set di risultati.

Inoltre:ho notato che stai eseguendo il tuo $stmt2 più e più volte all'interno del ciclo, ma restituirà lo stesso risultato ogni volta. In base al principio di spostare il codice invariante del ciclo fuori dal ciclo, avresti dovuto eseguirlo una volta prima di avviare il ciclo e salvare il risultato in una variabile PHP. Quindi, indipendentemente dall'utilizzo di query memorizzate nel buffer o fetchAll(), non è necessario nidificare le query.

Quindi consiglierei di scrivere il codice in questo modo:

$sql ='SELECT temp_id FROM temp1';
$stmt2 = db::db()->prepare($sql);
$stmt2->execute();
$rs2 = $stmt2->fetchAll(PDO::FETCH_ASSOC);
$stmt2->closeCursor();

$sql='SELECT COUNT(*) AS valid FROM cities_has_zipcodes 
      WHERE cities_id=:cities_id AND zipcodes_id=:zipcodes_id';
$stmt1 = db::db()->prepare($sql);

foreach($data AS $row)
{
    try
    {
        $stmt1->execute($row);
        $rs1 = $stmt1->fetchAll(PDO::FETCH_ASSOC);
        $stmt1->closeCursor();
        syslog(LOG_INFO,'$rs1: '.print_r($rs1[0],1).' '.rand());
        syslog(LOG_INFO,'$rs2: '.print_r($rs2[0],1).' '.rand());
    }
    catch(PDOException $e){echo(sql_error($e));}            
}

Nota che ho anche usato parametri denominati invece di parametri posizionali, il che semplifica il passaggio di $ riga come matrice di valori dei parametri. Se le chiavi dell'array corrispondono ai nomi dei parametri, puoi semplicemente passare l'array. Nelle versioni precedenti di PHP dovevi includere il : prefisso nelle chiavi dell'array, ma non ne hai più bisogno.

Dovresti comunque usare mysqlnd. Ha più funzioni, è più efficiente in termini di memoria e la sua licenza è compatibile con PHP.