web-dev-qa-db-fra.com

PDO :: fetchAll vs PDO :: fetch dans une boucle

Juste une petite question.

Existe-t-il une différence de performances entre l'utilisation de PDO :: fetchAll () et PDO :: fetch () dans une boucle (pour les grands ensembles de résultats)?

Je vais chercher dans les objets d'une classe définie par l'utilisateur, si cela fait une différence.

Mon hypothèse initiale non éduquée était que fetchAll pourrait être plus rapide car PDO peut effectuer plusieurs opérations dans une seule instruction alors que mysql_query ne peut en exécuter qu'une seule. Cependant, je connais peu le fonctionnement interne de PDO et la documentation ne dit rien à ce sujet, et si fetchAll () est simplement une boucle côté PHP déversée dans un tableau.

De l'aide?

68
Lotus Notes

Petite référence avec 200 000 enregistrements aléatoires. Comme prévu, la méthode fetchAll est plus rapide mais nécessite plus de mémoire.

Result :
fetchAll : 0.35965991020203s, 100249408b
fetch : 0.39197015762329s, 440b

Le code de référence utilisé:

<?php
// First benchmark : speed
$dbh = new PDO('mysql:dbname=testage;dbhost=localhost', 'root', '');
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = 'SELECT * FROM test_table WHERE 1';
$stmt = $dbh->query($sql);
$data = array();
$start_all = microtime(true);
$data = $stmt->fetchAll();
$end_all = microtime(true);

$stmt = $dbh->query($sql);
$data = array();
$start_one = microtime(true);
while($data = $stmt->fetch()){}
$end_one = microtime(true);

// Second benchmark : memory usage
$stmt = $dbh->query($sql);
$data = array();
$memory_start_all = memory_get_usage();
$data = $stmt->fetchAll();
$memory_end_all = memory_get_usage();

$stmt = $dbh->query($sql);
$data = array();
$memory_end_one = 0;
$memory_start_one = memory_get_usage();
while($data = $stmt->fetch()){
  $memory_end_one = max($memory_end_one, memory_get_usage());
}

echo 'Result : <br/>
fetchAll : ' . ($end_all - $start_all) . 's, ' . ($memory_end_all - $memory_start_all) . 'b<br/>
fetch : ' . ($end_one - $start_one) . 's, ' . ($memory_end_one - $memory_start_one) . 'b<br/>';
74
Arkh

Une chose à propos de PHP que j'ai trouvée vraie presque toujours est qu'une fonction que vous implémentez vous-même sera presque toujours plus lente que la PHP équivalent. En effet, quand quelque chose est implémenté en PHP il n'a pas toutes les optimisations de temps de compilation que C a (qui PHP est écrit en) et il y a une surcharge élevée d'appels de fonction PHP.

10
Kendall Hopkins

tous les repères au-dessus desquels mesurer "l'empreinte mémoire" sont en fait incorrects pour la raison très simple.

Par défaut, PDO charge toutes les choses dans la mémoire et peu importe si vous utilisez fetch ou fetchAll. Pour vraiment profiter des avantages de la requête sans tampon, vous devez demander à PDO d'utiliser les requêtes sans tampon:

$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

Dans ce cas, vous verrez une énorme différence dans l'empreinte mémoire du script

9
iVariable

@Arkh

// $data in this case is an array of rows;

$data = $stmt->fetchAll();


// $data in this case is just one row after each loop;

while($data = $stmt->fetch()){}


// Try using

$i = 0;

while($data[$i++] = $stmt->fetch()){}

La différence de mémoire devrait devenir négligeable

9
Mihai Stancu

Comme le disait Mihai Stancu, il n'y a presque pas de différence de mémoire bien que fetchAll bat fetch + while.

Result : 
fetchAll : 0.160676956177s, 118539304b
fetch : 0.121752023697s, 118544392b

J'ai obtenu les résultats ci-dessus en exécutant correctement:

$i = 0;
while($data[$i++] = $stmt->fetch()){
    //
}

Ainsi, fetchAll consomme moins de mémoire, mais fetch + while est plus rapide! :)

4
Rihards

Mais sûrement, si vous stockez les données extraites dans un tableau, l'utilisation de la mémoire sera égale?

<?php
define('DB_Host', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
// database to use
define('DB', 'test');
try
{
   $dbh = new \PDO('mysql:dbname='. DB .';Host='. DB_Host, DB_USER, DB_PASS);   $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $sql = 'SELECT * FROM users WHERE 1';
   $stmt = $dbh->query($sql);
   $data = array();
   $start_all = microtime(true);
   $data = $stmt->fetchAll();
   $end_all = microtime(true);

   $stmt = $dbh->query($sql);
   $data = array();
   $start_one = microtime(true);
   while($data = $stmt->fetch()){}
   $end_one = microtime(true);

   // Second benchmark : memory usage
   $stmt = $dbh->query($sql);
   $data = array();
   $memory_start_all = memory_get_usage();
   $data = $stmt->fetchAll();
   $memory_end_all = memory_get_usage();

   $stmt = $dbh->query($sql);
   $data = array();
   $memory_end_one = 0;
   $memory_start_one = memory_get_usage();
   while($data[] = $stmt->fetch()){
     $memory_end_one = max($memory_end_one, memory_get_usage());
   }

   echo 'Result : <br/>
   fetchAll : ' . ($end_all - $start_all) . 's, ' . ($memory_end_all - $memory_start_all) . 'b<br/>
   fetch : ' . ($end_one - $start_one) . 's, ' . ($memory_end_one - $memory_start_one) . 'b<br/>';
}
catch ( PDOException $e )
{
   echo $e->getMessage();
}
?>

Result : 
fetchAll : 2.6941299438477E-5s, 9824b
fetch : 1.5974044799805E-5s, 9824b
3
Andy

Je sais que c'est un vieux sujet, mais je le rencontre avec la même question. Ayant exécuté mon propre "benchmark" simple et lu ce que les autres ont écrit ici, je suis arrivé à la conclusion que ce n'est pas une science exacte et même si l'on devrait s'efforcer d'écrire la qualité, le code léger, il n'y a aucun intérêt à perdre trop de temps au début du projet.

Ma suggestion est la suivante: collectez des données en exécutant le code (en version bêta?) Pendant un certain temps, puis commencez à optimiser.

Dans mon benchmark simple (temps d'exécution testé uniquement), j'ai obtenu des résultats variant entre 5% et 50% dans les deux sens. J'exécute les deux options dans le même script, mais lorsque j'exécute fetch + en premier, il a été plus rapide que fetchall et vice versa. (Je sais que j'aurais dû les exécuter individuellement et quelques centaines de fois pour obtenir la médiane et la moyenne, puis comparer, mais - comme je l'ai dit au début - j'ai conclu que dans mon cas, il est trop tôt pour commencer à le faire.)

2
StrayObject