Benchmark Apache: doctrine hydrate object vs array
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: apache, benchmark, doctrine, hydrate, performance, Symfony
6 Réponses
Laisser un message

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.
merci ! très intéressant
@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!
[...] Benchmark array vs object dans Doctrine : instructif [...]
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…
[...] 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 [...]