Mysql
 sql >> Base de données >  >> RDS >> Mysql

Causes de l'erreur MySQL 2014 Impossible d'exécuter des requêtes alors que d'autres requêtes non tamponnées sont actives

Le protocole client MySQL n'autorise pas plus d'une requête "en cours". Autrement dit, vous avez exécuté une requête et vous avez récupéré certains des résultats, mais pas tous, puis vous essayez d'exécuter une seconde requête. Si la première requête a encore des lignes à renvoyer, la deuxième requête obtient une erreur.

Les bibliothèques clientes contournent ce problème en récupérant tous les lignes de la première requête implicitement lors de la première extraction, puis les extractions suivantes itèrent simplement sur les résultats mis en cache en interne. Cela leur donne la possibilité de fermer le curseur (en ce qui concerne le serveur MySQL). Il s'agit de la "requête tamponnée". Cela fonctionne de la même manière que l'utilisation de fetchAll(), en ce sens que les deux cas doivent allouer suffisamment de mémoire dans le client PHP pour contenir l'ensemble des résultats complets.

La différence est qu'une requête mise en mémoire tampon contient le résultat dans la bibliothèque client MySQL, de sorte que PHP ne peut pas accéder aux lignes tant que vous n'avez pas récupéré chaque ligne de manière séquentielle. Alors que fetchAll() remplit immédiatement un tableau PHP pour tous les résultats, vous permettant d'accéder à n'importe quelle ligne aléatoire.

La raison principale non utiliser fetchAll() est qu'un résultat peut être trop volumineux pour tenir dans votre PHP memory_limit. Mais il semble que les résultats de votre requête n'aient qu'une seule ligne de toute façon, donc cela ne devrait pas poser de problème.

Vous pouvez closeCursor() pour "abandonner" un résultat avant d'avoir récupéré la dernière ligne. Le serveur MySQL est informé qu'il peut supprimer ce résultat côté serveur, puis vous pouvez exécuter une autre requête. Vous ne devez pas fermerCursor() tant que vous n'avez pas fini de récupérer un ensemble de résultats donné.

Aussi:je remarque que vous exécutez votre $stmt2 encore et encore à l'intérieur de la boucle, mais il renverra le même résultat à chaque fois. Sur le principe du déplacement du code invariant de la boucle hors de la boucle, vous devriez l'avoir exécuté une fois avant de démarrer la boucle et enregistré le résultat dans une variable PHP. Ainsi, que vous utilisiez des requêtes mises en mémoire tampon ou fetchAll(), vous n'avez pas besoin d'imbriquer vos requêtes.

Je vous recommande donc d'écrire votre code de cette façon :

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

Notez que j'ai également utilisé des paramètres nommés au lieu de paramètres positionnels, ce qui simplifie le passage de $row comme tableau de valeurs de paramètres. Si les clés du tableau correspondent aux noms des paramètres, vous pouvez simplement passer le tableau. Dans les anciennes versions de PHP, vous deviez inclure le : préfixe dans les clés du tableau, mais vous n'en avez plus besoin.

Vous devriez utiliser mysqlnd de toute façon. Il a plus de fonctionnalités, il est plus économe en mémoire et sa licence est compatible avec PHP.