while versus alles ineens
Een kort vraagje. Als ik 20 producten uit de database wil halen dan kan ik in PDO via fetchAll() al deze producten in 1 keer ophalen. Nu zie ik ook regelamtig de "while" constructie voorbijkomen, en ik vraag me af wat daar het voordeel van is:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$products = '';
while ($row = $result->fetch()) {
$products .= '<div class="product">' . $row->description . '</div>';
}
?>
$products = '';
while ($row = $result->fetch()) {
$products .= '<div class="product">' . $row->description . '</div>';
}
?>
Dit levert toch gewoon hetzelfde resultaat op?
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$result = $result->fetchAll();
$products = '';
foreach ($result as $product) {
$products .= '<div class="product">' . $product->description . '</div>';
}
?>
$result = $result->fetchAll();
$products = '';
foreach ($result as $product) {
$products .= '<div class="product">' . $product->description . '</div>';
}
?>
Waarom ik dit vraag?
Ik heb nu een eigen databse class gemaakt die PDO extend. De method om gegevens op te halen heb ik fetch() genoemd. Echter, fetch() is ook een method van PDO die ik nu dus met mijn eigen method overschrijf. Dit levert op zich geen problemen op, tenzij ik ooit die "while" constructie nodig zou hebben. Daarom ben ik dus benieuwd wat daarvan de meerwaarde is, als er überhaupt een meerwaarde is.
Graag jullie reactie.
Gewijzigd op 02/06/2013 15:02:38 door Ozzie PHP
Is fetchAll() niet gewoon een interne functie die door middel van de while() alles in een array gooit en dan teruggeeft?
PDOStatement is ook gewoon een iterator, dus dat kun je ook gebruiken.
Oké, maar wat is nu het verschil tussen mijn beide codevoorbeelden? Maakt het iets uit?
Ozzie PHP op 02/06/2013 21:19:55:
Het is een klassieke trade-off in performance: fetchAll() is sneller maar verbruikt daarvoor in ruil meer geheugen dan fetch().Oké, maar wat is nu het verschil tussen mijn beide codevoorbeelden? Maakt het iets uit?
Verder hangt het af van wat je in de loop wilt kunnen doen. Als de loop bijvoorbeeld voortijdig verlaten kan worden met break, als de loop een redirect uitvoert of als de loop het script beëindigt met een error, dan is alles ophalen met fetchAll() niet nodig.
"Het is een klassieke trade-off in performance: fetchAll() is sneller maar verbruikt daarvoor in ruil meer geheugen dan fetch()."
Nu wordt hierboven gezegd dat fetchAll in feite ook gewoon een while uitvoert. Waar zit dan precies dat verschil in snelheid versus geheugen?
"Verder hangt het af van wat je in de loop wilt kunnen doen. Als de loop bijvoorbeeld voortijdig verlaten kan worden met break, als de loop een redirect uitvoert of als de loop het script beëindigt met een error, dan is alles ophalen met fetchAll() niet nodig."
Ik snap wat je bedoelt. Komt zoiets in de praktijk vaak voor dat jij weet? Dat je de loop vroegtijdig moet verlaten op basis van input vanuit de database? (misschien een voorbeeldje?)
Als je een gerichte (goede) query schrijft, zou het inderdaad niet veel moeten uitmaken, omdat je toch uitsluitend ophaalt wat je nodig hebt en verder niets. Maar in de praktijk wil je misschien in PHP nog wat controles uitvoeren die je niet kon formaliseren in de query. Dat is dan de voornaamste afweging.
Gewijzigd op 03/06/2013 12:10:34 door Ward van der Put
"Is fetchAll() niet gewoon een interne functie die door middel van de while() alles in een array gooit en dan teruggeeft?"
Anyhow... welke methode gebruik jij zelf het meest? Ben jij zelf wel eens in een situatie gekomen waarin het per rij fetchen handiger was dan alles in 1x fetchen?
Bedankt trouwens voor de uitleg van hoe een SELECT query werkt icm een recordset. Zo had ik het zelf ook bedacht, maar ben blij dat jij dat nu even bevestigd hebt :)
Vraag is meer of je die complete recordset in het PHP-geheugen wilt laden. Soms wel, soms niet. Ik denk namelijk niet dat er één methode is die altijd het beste werkt; in een databaseklasse op basis van PDO zou ik daarom beide gebruiken. Of anders gezegd: ik zou me niet bij voorbaat tot één van beide beperken als ik beide tot mijn beschikking heb.
"Vraag is meer of je die complete recordset in het PHP-geheugen wilt laden."
Misschien een rare vraag, maar waarom zou je het niet willen? Je voert bewust een bepaalde SELECT query uit. Die gegevens wil je dan toch ook daadwerkelijk binnenhalen? Anders gezegd. Stel ik selecteer 10 producten, dan wil ik daar dus blijkbaar iets mee doen. Dan zal ik ze toch altijd in het geheugen moeten laden?
Ozzie PHP op 03/06/2013 12:26:36:
Nee, dat hoeft niet. Stel, je wilt die 10 producten tonen in een HTML-tabel. Je hoeft dan in PHP alleen de <tr>...</tr> per product op te slaan, niet de achterliggende 10 records. En dan kun je de 10 tabelrijen dus ook één voor één opstellen met fetch().Misschien een rare vraag, maar waarom zou je het niet willen? Je voert bewust een bepaalde SELECT query uit. Die gegevens wil je dan toch ook daadwerkelijk binnenhalen? Anders gezegd. Stel ik selecteer 10 producten, dan wil ik daar dus blijkbaar iets mee doen. Dan zal ik ze toch altijd in het geheugen moeten laden?
Inderdaad: zodra je 'iets' hebt gedaan met een rij uit de recordset, heb je die vaak niet meer nodig. Dan kan een echo zijn, maar bijvoorbeeld ook het opslaan van een tabelrij in een array of het wijzigen van een eigenschap van een object. De huidige rij uit de database kan dan verder vergeten worden en in de loop worden vervangen door een volgende rij.
Als je trouwens dit zou doen:
Code (php)
en je gooit daar vervolgens een unset achteraan...
Levert dat dan hetzelfde resultaat op?
Als je in de view een array verwacht of een soortgelijke datastructuur of datacontainer, dan is het inderdaad logischer om die in één ruk te vullen met fetchAll().
Ik vindt het programeer technisch gezien eigenlijk gewoon onlogisch om rij voor rij op te halen, dit genereert alleen maar meer netwerk traffic.
Ward van der Put op 03/06/2013 14:36:40:
Als je in de view een array verwacht of een soortgelijke datastructuur of datacontainer, dan is het inderdaad logischer om die in één ruk te vullen met fetchAll().
Oké.
Ger van Steenderen op 03/06/2013 17:53:27:
Ik heb altijd gedacht dat een recordset in één keer van de db server af gehaald wordt, in PHP manual spreekt men ook van een result set als resultaat van een query.
Ik vindt het programeer technisch gezien eigenlijk gewoon onlogisch om rij voor rij op te halen, dit genereert alleen maar meer netwerk traffic.
Ik vindt het programeer technisch gezien eigenlijk gewoon onlogisch om rij voor rij op te halen, dit genereert alleen maar meer netwerk traffic.
Ik vind het ook niet handig om rij voor rij op te halen. Maar volgens mij haal je dus op basis van je query een resultset op. Deze resultset staat dan op de databaseserver. Met fetch haal je er dan telkens 1 rij vanaf, en met fetchAll haal je alles in 1x op. Op het moment dat je iedere rij meteen op het beeld zou echo'en, zou je de rijen dus niet op te hoeven slaan in het geheugen en daarmee bespaar je dus geheugen. Echter, in de moderne programmeerstijlen denk ik niet dat het logisch is om het resultaat van je query direct naar het beeldscherm te echo'en. FetchAll lijkt me dan in de meeste gevallen ook de logische keuze.
Maar als jij en Ward gelijk hebben (waarvan ik -nog- niet helemaal overtuigd ben) is die fetch gewoon zinloos geweld.
Je zou dan dus geheugen besparen in PHP, maar op de db server kost het je geheugen.
Daarnaast zou je dus als je bv 40 rijen ophaalt, 39 extra client-server op-en-neertjes krijgen.
Keuze lijkt mij niet zo moeilijk
Als je fetchAll gebruikt is dit wel het geval.
Volgens mij is het zo dat je dus een SQL statement hebt SELECT blabla FROM...
Vervolgens execute() of query() je dit statement $stmt->execute(). Door dit te doen wordt er een resultset klaargezet op de databaseserver. Alle rijen zijn nu dus al opgehaald uit de database.
Door fetchAll te gebruiken haal je in 1x alle rijen binnen in PHP. Echter door fetch te gebruiken haal je telkens 1 rij binnen. VOlgens mij is dit hoe het werkt, maar pin me er niet voor 100% op vast. Ward, klopt mijn verhaal?
Ozzie PHP op 03/06/2013 22:57:30:
Ja, dat klopt. Verbreek maar eens de databaseverbinding midden in een loop die rijen ophaalt. Of wat je ook kunt doen: verplaats de cursor terug naar een eerder gelezen rij.Door fetchAll te gebruiken haal je in 1x alle rijen binnen in PHP. Echter door fetch te gebruiken haal je telkens 1 rij binnen. VOlgens mij is dit hoe het werkt, maar pin me er niet voor 100% op vast. Ward, klopt mijn verhaal?
Bij "in één keer" kan ik me technisch niet veel voorstellen. Bij PDO::fetchAll() krijg je namelijk een PHP-array, een nogal typische datastructuur. En PDO moet die PHP-array genereren via de recordsets van uiteenlopende databaseplatforms. Bijvoorbeeld een MySQL-recordset wordt niet "in één keer" een PHP-array. Je kunt allicht in de PDO-code duiken, maar ik vermoed dat het toch achter de schermen met iteraties wordt gedaan.
Gewijzigd op 04/06/2013 06:56:11 door Ward van der Put
Ward van der Put op 04/06/2013 06:55:43:
Je kunt allicht in de PDO-code duiken, maar ik vermoed dat het toch achter de schermen met iteraties wordt gedaan.
Je bedoelt dat er sowieso een soort van while loop wordt uitgevoerd? Dit zou dan inhouden dat het niet uitmaakt als je zelf de rijen met een "while" constructie ophaalt, of dat je fetchAll gebruikt omdat die laatste achter de schermen waarschijnlijk dan ook een soort "while" constructie gebruikt. Maar inderdaad, het blijft gissen...