70 votes

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

Juste une petite question.

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

Je récupère les objets d'une classe définie par l'utilisateur, si cela fait une différence.

Ma supposition initiale non éclairée était que fetchAll pourrait être plus rapide parce que PDO peut effectuer plusieurs opérations dans une déclaration alors que mysql_query ne peut en exécuter qu'une. Cependant, j'ai peu de connaissances sur le fonctionnement interne de PDO et la documentation ne dit rien à ce sujet, et si oui ou non fetchAll() est simplement une boucle côté PHP vidée dans un tableau.

Une aide ?

76voto

Arkh Points 5804

Petit benchmark avec 200k 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/>';

10voto

Kendall Hopkins Points 12193

Une chose à propos de PHP que j'ai trouvée vraie presque toujours. toujours est qu'une fonction que vous implémentez vous-même sera presque toujours plus lente que l'équivalent PHP. Ceci est dû au fait que lorsque quelque chose est implémenté en PHP, il n'y a pas toutes les optimisations à la compilation que le C a (en lequel PHP est écrit) et il y a une forte surcharge des appels de fonctions PHP.

9voto

Mihai Stancu Points 51

@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

4voto

Richards Points 2032

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

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

J'ai obtenu les résultats ci-dessus avec un fonctionnement correct :

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

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

4voto

Andy Points 31

Mais si vous stockez les données extraites dans un tableau, l'utilisation de la mémoire sera certainement é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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X