Waarom is ADODB bij mij sneller dan PDO?
Ben bezig voor een bedrijf die een oude PHP applicatie heeft. Ik bouw dat ding zo goed als helemaal om, omdat het nogal veel spaghetticode bevat. Dat lukt aardig, maar nu zag ik dus ook dat bij het opvragen van data uit de database het oude ADODB wordt gebruikt. Dus ik dacht, ik ga daar PDO van maken, want ik lees overal dat dit sneller is.
Dat test ik dan gelijk op een van de zwaarste requests in de applicatie en wat schetst mijn verbazing: ADODB is 2 seconden sneller dan als ik die query via PDO uitvoer. Huh?! Logischerwijs moet er iets zijn wat ik mis dus ik vraag nu, kunnen jullie mij hints geven waar ik naar moet zoeken?
Hieronder een snel voorbeeld van mij om een array op te vragen via PDO. Dat komt omdat de hele app vol zit met iterations over een array dus ik dacht, ik start dan maar eerst met een array.
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
$dsn = "mysql:host=". MYSQL_HOST . ";dbname=" . MYSQL_DB . ";port=" . MYSQL_PORT . "charset=" . MYSQL_CHARSET;
try {
$pdo = new PDO($dsn, MYSQL_USER, MYSQL_PASS, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
$statement = $pdo->query($sql);
return ($statement !== false ? $statement : null);
try {
$pdo = new PDO($dsn, MYSQL_USER, MYSQL_PASS, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
$statement = $pdo->query($sql);
return ($statement !== false ? $statement : null);
De oude ADODB code doet dit:
Een array maken wordt op deze manier gedaan:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
$this->_recordcount = $rs->RecordCount();
$this->found_rows();
while (!$rs->EOF) {
$arr[$rs->fields[$this->pKey]] = $rs->fields;
$rs->moveNext();
}
$this->found_rows();
while (!$rs->EOF) {
$arr[$rs->fields[$this->pKey]] = $rs->fields;
$rs->moveNext();
}
Je ziet een extra "RecordCount" en dan ook nog een "found_rows()" call. Dus er worden extra queries uitgevoerd, vervolgens wordt er een array gemaakt door over het huidige resultaat te iteraten, en vervolgens ergens anders in de code wordt er over die array geitereerd om het resultaat weer te geven. 3 tot 4x teveel over het resultaat heen, teveel queries etcetera. Je snapt mijn verbazing dat als ik dat allemaal niet doe en het via PDO doe het ineens langer duurt.
Bedankt voor de hulp.
Groet
Maarten
Gewijzigd op 18/06/2021 12:05:04 door Maarten Baars
Ik zou eens een Profiler (XDebug bijv.) loslaten op je applicatie, die splitst netjes per functie-call en classname uit hoe veel tijd er in gaat zitten, vanaf daar kun je gaan analyseren of het écht in PDO zit of dat je onbedoeld iets doet wat niet bijster efficiënt is.
Bedankt voor je input. Laat ik voor het gemak het proces eens versimpelen:
ADODB->query => Itereren over resultaat => berekeningen doen => toon uitkomst (9 seconden)
Jouw idee is, wellicht kan de tijd gaan zitten in dat itereren over het resultaat en/of de berekeningen. Feitelijk heb je ook gelijk, want daarin worden nóg meer queries uitgevoerd en de applicatie waar ik aan werk zit vol met spaghetti. Maar als ik 1 element in dat proces aanpas, namelijk we gebruiken PDO, dan zou je zeggen dat stap 1 sneller zou moeten gaan en je dus in ieder geval:
A. Quitte speelt
óf
B. Snelheidswinst krijgt
PDO->query => Itereren over resultaat => berekeningen doen => toon resultaat (11 seconden)
Verbazing alom dus. Want hoe kan het, ookal is de code shit, dat mét PDO hetzelfde proces langer duurt dan anders? Het resultaat van de query is namelijk exact hetzelfde opgebouwd (array). Sterker nog, de code die met ADODB de data ophaalde deed tenminste nog 1 extra iteratie over de gehele resultatenset om zo een aangepaste array te maken waarbij de Primary key als array key werd ingesteld. Een totaal onnodige actie waarvan ik dacht megaveel snelheidswinst te kunnen pakken. Want met de PDO versie haal ik gewoon data op en geef die zonder dat extra gedoe terug.
De snelheidsdata is verkregen door in Firefox de debugdata op te halen met F12.
Dank
Maarten
Gewijzigd op 18/06/2021 14:51:01 door Maarten Baars
Als beide queries hetzelfde zijn, ligt de 2 seconden vertraging in de I/O met de database driver. Dat kan verklaard worden door een verschil in instellingen, bijvoorbeeld: query je wel op hetzelfde schema, maakt de ene gebruik van TLS en de andere niet, staan de instellingen voor encoding goed of wordt alle I/O getranscodeerd?
Als er een verschil zit op de queries moet je daar goed naar kijken. Verschil in prestaties kan verklaard worden door net even anders groeperen of nesten van queries tot domweg onhandig of geen gebruik maken van indices. Je krijgt het boven water met de SQL keywords EXPLAIN en ANALYSE.
Maarten Baars op 18/06/2021 14:48:23:
PDO->query => Itereren over resultaat => berekeningen doen => toon resultaat (11 seconden)
Verbazing alom dus. Want hoe kan het, ookal is de code shit, dat mét PDO hetzelfde proces langer duurt dan anders?
...
De snelheidsdata is verkregen door in Firefox de debugdata op te halen met F12.
Verbazing alom dus. Want hoe kan het, ookal is de code shit, dat mét PDO hetzelfde proces langer duurt dan anders?
...
De snelheidsdata is verkregen door in Firefox de debugdata op te halen met F12.
Dat is niet echt een goede test om enkel de duur van de DB query te vergelijken.
Je introduceert namelijk nogal wat overhead in de vorm van een HTTP(S) request en het opzetten van de database connectie en alle overige code in je applicatie.
Het zou best kunnen dat het optuigen van een PDO connectie en bijbehorende classes langer duurt dan bij ADODB, die overhead zit er nu ook in.
Ik zou toch eens een profiler zoals XDebug loslaten op je applicatie, of in ieder geval alleen de duur van alleen de query meten d.m.v. microtime.
Iets als onderstaand dus:
Code (php)
Meten is weten en hoe specifieker je je meting maakt hoe beter je weet waar het verschil vandaan komt.
Gewijzigd op 19/06/2021 17:41:59 door Thom nvt
Maarten Baars op 18/06/2021 12:04:02:
nu zag ik dus ook dat bij het opvragen van data uit de database het oude ADODB wordt gebruikt. Dus ik dacht, ik ga daar PDO van maken, want ik lees overal dat dit sneller is.
Met "oude ADODB" doe je ADODB te kort, er is een recente 2021 release beschikbaar als je na de testen toch besluit om met ADODB door te gaan. Het is zinvol om de test die Thom aanraadt uit te voeren. Daarnaast is het zinvol om je query's ook te beoordelen. Waarom na het ophalen van data nog itereren in PHP? Is de query niet slimmer te maken die het itereren overbodig maakt?
Gewijzigd op 20/06/2021 22:37:11 door John D