Benchmark Apache: doctrine hydrate object vs array

clock Il faut se rendre à l’évidence, défendre une idée sans argument, c’est bien souvent très compliqué. Et quand il a fallu que j’arrive à quantifier le réel apport d’une hydratation en tableau plutôt qu’en object, c’était un peu difficile. Rappelez-vous, j’en avais parlé dans les secrets de doctrine.

Je me suis donc dis que j’allais tout simplement le benchmarker grosso modo, afin d’avoir une idée du gain qu’on peut avoir à passer par des tableaux. Car en fait, on sait très bien que le 2e est plus rapide, mais la question, c’est de combien.

J’ai donc pris un modèle assez classique. Un couple de Departement/Region de France.

Dans mon fichier Table de mes départements, je rajoute la méthode suivante pour faire ma jointure sur régions

public function getAll()
  {
    return $this->createQuery('d')
      ->leftJoin('d.Regions r');
  }

Hydratation en objet

Parfait, maintenant, je crée une action qui récupère seulement tous les items de ma table, soit environ 100 départements, en relation avec une région chacun.

public function executeIndex(sfWebRequest $request)
  {
    $this->items = Doctrine::getTable('Departements')->getAll()->execute();
  }

Ca reste un cas tout a fait commun. J’ai donc lancé un ab, un programme livré avec apache qui permet de lancer l’exécution d’une page web, n fois avec n requêtes concurrentielles. j’ai décidé de le lancer 100 fois avec 10 requêtes à la fois. Et voici le résultat:

Document Path:          /hydrate/index
Document Length:        2400 bytes
 
Concurrency Level:      10
Time taken for tests:  16.862 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      269400 bytes
HTML transferred:       240000 bytes
Requests per second:    5.93 [#/sec] (mean)
Time per request:       1686.205 [ms] (mean)
Time per request:       168.621 [ms] (mean, across all concurrent requests)
Transfer rate:          15.60 [Kbytes/sec] received
 
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.5      0       4
Processing:  1172 1665 167.3   1662    2337
Waiting:     1172 1663 166.5   1661    2337
Total:       1172 1665 167.4   1662    2338
 
Percentage of the requests served within a certain time (ms)
  50%   1662
  66%   1709
  75%   1750
  80%   1783
  90%   1860
  95%   1928
  98%   2102
  99%   2338
 100%   2338 (longest request)

Hydratation en tableau

2e action, le même code, le même résultat HTML souhaité, mais on passe dans le execute le fameux paramètre. Notre résultat ne sera donc plus une Doctrine_Collection, mais un tableau associatif avec en clé, les noms des champs.

  public function executeIndex2(sfWebRequest $request)
  {
    $this->items = Doctrine::getTable('Departements')->getAll()->execute(array(),Doctrine::HYDRATE_ARRAY);
  }

Et voici le résultat

Document Path:          /hydrate/index2
Document Length:        2400 bytes
 
Concurrency Level:      10
Time taken for tests:   10.086 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      269400 bytes
HTML transferred:       240000 bytes
Requests per second:    9.92 [#/sec] (mean)
Time per request:       1008.569 [ms] (mean)
Time per request:       100.857 [ms] (mean, across all concurrent requests)
Transfer rate:          26.09 [Kbytes/sec] received
 
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.4      0       6
Processing:   598  992 112.9   1003    1239
Waiting:      598  991 113.0   1002    1239
Total:        599  993 113.0   1003    1239
 
Percentage of the requests served within a certain time (ms)
  50%   1003
  66%   1051
  75%   1081
  80%   1085
  90%   1104
  95%   1128
  98%   1149
  99%   1239
 100%   1239 (longest request)

Bilan

Alors évidemment, il faut prendre en compte la différence de temps de réponse qu’on peut avoir entre 2 lancement de ab. Mais l’objectif est surtout de montrer que le gain est non négligeable et vraiment réel.

On constate que le HTML reçu est bien le même. On a donc le même rendu!
Et côté performance, le 1er cas nous donne une requête en 1,7sec quand le 2e nous donne 1s soit près de 60% de mieux.

Conclusion, quand on souhaite réaliser seulement de l’affichage de données, il faut hydrater en tableau! Même si dans le cas présent, on parle de 0,7sec, il faut voir que c’est un projet vierge avec rien d’autre autour. Le gain est donc bien réel et pas seulement gadget.

Crédit photo: http://www.flickr.com/photos/don3rdse/3208161023/

Tags: , , , , ,

A propos de l'auteur

Tim

Développeur web spécialisé Symfony, il est avant tout passionné de web tout simplement. Il aime les défis et farfouiller dans le code de Symfony ou Doctrine. Fondateur du blog, il exerce chez Autrement.

Vous avez aimé ce billet? Faites le savoir!

  • Delicious
  • Twitter
  • Technorati Favorites
  • FriendFeed
  • Google Bookmarks
  • Share/Bookmark

6 Réponses

  1. Sebastien 8 octobre 2009 à 15 h 30 min #

    Tu sais si ça existe sur Propel ? Je crois avoir déjà vu un truc comme ça ? Ou je me trompe peut être…

    En tout cas très intéressant ! Merci.

  2. jukea 9 octobre 2009 à 15 h 31 min #

    merci ! très intéressant

  3. Tim 10 octobre 2009 à 13 h 52 min #

    @Sebastien, il me semble aussi qu’il y a un système similaire dans Propel mais ça me parle pas plus.

    Si qulqu’un a des infos, qu’il hésite pas!

  4. [...] Benchmark array vs object dans Doctrine : instructif [...]

  5. theredled 11 novembre 2009 à 23 h 27 min #

    Intéressant, le problème restant qu’il est pour l’instant impossible d’avoir dans un tableau les données des getters custom…
    Perso c’est ce qui m’empêche d’utiliser les tableaux autant que je le voudrais.

    Ex : un champ « tva », un champ « prix_ht », et un getter getPrixTtc(). C’est un exemple très simple mais on peut aller loin comme ça.

    L’idéal serait de pouvoir hydrater non seulement le résultat de la requête, mais aussi certains getters custom…

  6. [...] Remplacez alors l’appel à ->execute() par ->fetchArray(). Un benchmark réalisé sur AmicalementWeb présente des gains de performances non négligeables pour la seconde méthode. Dans le cadre de [...]


Laisser un message