Maison  >  Article  >  développement back-end  >  Comment résoudre le problème de l'épuisement de la mémoire lors de la boucle de grandes quantités de données en PHP

Comment résoudre le problème de l'épuisement de la mémoire lors de la boucle de grandes quantités de données en PHP

coldplay.xixi
coldplay.xixiavant
2020-08-31 17:22:383589parcourir

Comment résoudre le problème de l'épuisement de la mémoire lors de la boucle de grandes quantités de données en PHP

Recommandations d'apprentissage associées : programmation php(vidéo)

J'ai récemment rencontré l'erreur suivante lors du développement d'un programme PHP :

Erreur fatale PHP : taille de mémoire autorisée de 268 435 456 octets épuisée

Le message d'erreur indique que la mémoire maximale autorisée a été épuisée. J'ai été surpris de rencontrer une telle erreur au début, mais après y avoir réfléchi, ce n'est pas surprenant, car le programme que je développe consiste à utiliser une instruction de boucle foreach pour rechercher la table entière dans une table contenant 40 000 enregistrements. des données avec des caractéristiques spécifiques, c'est-à-dire qu'il faut extraire 40 000 données à la fois, puis vérifier les données quotidiennes une par une. Il est concevable que si les 40 000 données étaient chargées dans la mémoire, il serait étrange que la mémoire n'éclate pas.

Après toutes ces années de programmation, je me souviens vaguement que PHP fournit une API qui ne charge pas les données en une seule fois. C'est une méthode de requête qui peut être utilisée et perdue comme le streaming multimédia, et les données ne le font pas. s'accumulent dans la mémoire. Après une simple recherche, j'ai trouvé l'utilisation correcte sur le site officiel.

Ce problème est appelé Requêtes tamponnées et non tamponnées sur le site officiel de PHP. Le mode de requête par défaut de PHP est le mode tamponné. En d’autres termes, les résultats des données de la requête seront extraits en mémoire d’un seul coup pour être traités par le programme PHP. Cela donne au programme PHP des fonctions supplémentaires, telles que compter le nombre de lignes, pointer le pointeur vers une certaine ligne, etc. Ce qui est plus important, c'est que le programme peut effectuer à plusieurs reprises des requêtes secondaires et des opérations de filtrage sur l'ensemble de données. Cependant, l’inconvénient de ce mode de requête tamponné est qu’il consomme de la mémoire, c’est-à-dire qu’il échange de l’espace contre de la vitesse.

En revanche, un autre mode de requête PHP est une requête sans tampon. Le serveur de base de données renverra les données une par une au lieu de toutes en même temps. Le résultat est que le programme PHP consomme moins de mémoire, mais augmente la mémoire. consommation. La pression sur le serveur de base de données, car la base de données attendra que PHP récupère les données jusqu'à ce que toutes les données soient récupérées.

Évidemment, le mode de requête tamponné convient aux requêtes avec de petits volumes de données, tandis que les requêtes non tamponnées conviennent aux requêtes avec de gros volumes de données.

Tout le monde connaît la requête en mode tamponné de PHP. L'exemple ci-dessous montre comment exécuter l'API de requête non tamponnée.

Méthode de requête sans tampon 1 : mysqli

<?php
$mysqli  = new mysqli("localhost", "my_user", "my_password", "world");
$uresult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);

if ($uresult) {
   while ($row = $uresult->fetch_assoc()) {
       echo $row[&#39;Name&#39;] . PHP_EOL;
   }
}
$uresult->close();
?>

Méthode de requête sans tampon deux : pdo_mysql

<?php
$pdo = new PDO("mysql:host=localhost;dbname=world", &#39;my_user&#39;, &#39;my_pass&#39;);
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$uresult = $pdo->query("SELECT Name FROM City");
if ($uresult) {
   while ($row = $uresult->fetch(PDO::FETCH_ASSOC)) {
       echo $row[&#39;Name&#39;] . PHP_EOL;
   }
}
?>

Méthode de requête sans tampon trois : mysql

<?php
$conn = mysql_connect("localhost", "my_user", "my_pass");
$db   = mysql_select_db("world");

$uresult = mysql_unbuffered_query("SELECT Name FROM City");
if ($uresult) {
   while ($row = mysql_fetch_assoc($uresult)) {
       echo $row[&#39;Name&#39;] . PHP_EOL;
   }
}
?>

php Les internautes chinois se sont plaints :

Cette chose devrait utiliser un générateur

Cette façon d'écrire peut être ouverte directement

C'est impossible pour traiter le big data Écrit de cette manière

L'internaute chinois PHP Xiao Chen a donné une manière correcte

<?php

if (!function_exists(&#39;getYieldBigData&#39;)) {
    /**
     * 使用生成器返回生成器对象
     * @param array $data
     * @return Generator
     */
    function getYieldBigData($data = [])
    {
        foreach ($data as $tmp_data) {
            yield $tmp_data;
        }
        unset($tmp_data);
    }
}


if (!function_exists(&#39;foreachBigData&#39;)) {
    /**
     * 循环大量数据使用生成器来制造值
     * @param array $data
     * @return array|false
     */
    function foreachBigData($data = [])
    {
        if (0 == count($data)) {
            return false;
        }
        $tmp = [];
        foreach (getYieldBigData($data) as $v) {
            $tmp[] = $v;
        }
        unset($v);
        return $tmp;
    }
}

//调用方法
/**
 * @var $data array
 */
$data = [];
/**
 * @var $ret array
 */
$ret = foreachBigData($data);

return $ret;

Les débutants peuvent également le lire Compris !

Comment résoudre le problème de lépuisement de la mémoire lors de la boucle de grandes quantités de données en PHP

Comme ci-dessus, cette méthode peut atteindre 1 million/fois !

Cet article provient du tutoriel graphique php du site Web php chinois L'auteur original : God of War Wukong, le deuxième éditeur du site Web php chinois.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer