Een blik op MySQLi III - Unbuffered queries
Soms moet je heel veel data ophalen van een query. Dit gebeurd meestal als je bijvoorbeeld rapportages aan het maken bent waarin je ook nog wat logica over de data moet halen. Nu is het zo dat met het standaard gebruik van mysqli, maar ook met de oude MySQL extensie uit PHP4, de complete resultset direct in het geheugen van PHP wordt geladen. Als je deze data zelf niet perse nodig hebt, maar alleen voor bijvoorbeeld wat berekeningen, is dat natuurlijk niet het meest efficiente wat je kunt doen.
Leave my memory alone!
Het principe werd in de originele MySQL extensie unbuffered queries genoemd. Je hebt dan ook een functie, je raad het nooit, mysql_unbuffered_query(). Wat zo'n functie dus doet is de query uitvoeren, maar vervolgens fijn nog even de daadwerkelijke data op de MySQL server laten. In MySQLi doen we dit met de methode $link->real_query():
-
$qryResult = $link->real_query("
-
SELECT
-
*
-
FROM
-
bestellingen b
-
INNER JOIN betaalstatus bs ON (b.id = bs.bestelling_id)
-
WHERE bs.status_code = 'REM1'
-
");
De query is nu uitgevoerd en de data is beschikbaar op de server. We moeten MySQL alleen nog even vertellen wat we precies willen doen ermee, er zijn namelijk twee opties:
- We kunnen het resultaat gaan gebruiken om er doorheen te
lopen, maar dan kunnen we geen operaties doen op de resultset die een
overzicht van de resultset vereisen. Denk hierbij aan
$result->data_seek() en $result->num_rows(). Dit kunnen we
aangeven met de methode $link->use_result() en is in feite de
manier om query data niet gebuffered te doorlopen. - We kunnen er ook voor kiezen om de resultset tijdelijk op te slaan in het geheugen en deze te gaan gebruiken. Eigenlijk ben je dan
weer gewoon terug bij wat $link->query() doet. De gehele data
wordt opgehaald. We kunnen dit aangeven met de methode
$link->store_result();
Vervolgens kunnen we gewoon zoals we gewend zijn de data ophalen van de database server met de uitzondering van het feit dat nu $link->real_query() nu niet het statement object retourneert, maar juist $link->use_result() of $link->store_result():
-
/* We weten niet precies hoeveel business rules we gaan
-
* uitvoeren en welke data zij precies nodig
-
* hebben. Daarom halen we alle bestellings info op. */
-
-
$qryResult = $link->real_query("
-
SELECT
-
b.*
-
FROM
-
bestellingen b
-
INNER JOIN betaalstatus bs ON (b.id = bs.bestelling_id)
-
WHERE bs.status_code = 'REM1'
-
");
-
-
/* Laat de data op de server, en ga het pas ophalen als ik
-
er om vraag */
-
-
$resultSet = $link->use_result();
-
-
/* Een simpele business rule die volstrekt
-
willekeurig bestellingen met een REM1 (Reminder 1)
-
status kwijtscheldt. */
-
-
$bizRule = new WillekeurigeKwijtscheldingSpecification();
-
-
while ( $dataRow = $resultSet->fetch_assoc())
-
{
-
if ( $bizRule->isSatisfiedBy($dataRow) ) {
-
$kwijtScheldingIds[] = $dataRow['id'];
-
}
-
}
-
-
$resultSet->close();
-
-
// Doe hier iets leuks met $kwijtScheldingIds;
Een paar gotcha's
Waar het met $link->query() niet zeer belangrijk is om direct de gegevens weer vrij te geven als je klaar bent (PHP doet dat voor je immers) is het bij dit soort queries juist zeer belangrijk: zolang de resultset op de MySQL server in gebruik is, is het niet mogelijk om de tabellen waarin de data van de resultset is opgeslagen te wijzigen of toe te voegen.
Tevens lijkt het niet mogelijk om een prepared statement unbuffered uit te laten voeren, althans, ik kon hierover niet iets zinnigs vinden in de PHP handleiding voor MySQLi.
Conclusie
Gebruik de unbuffered queries als je veel data moet ophalen die op -zich- niet in het geheugen geladen hoeft te worden. Denk aan een scenario waar je bepaalde logica moet toepassen op de individuele rijen van een resultaat, maar je hoeft deze rijen vervolgens niet te tonen of verder in het geheugen te houden.
Volg Scriptorama via RSS!
Reageer ook!
[...] MySQLi III - Unbuffered queries [...]
Door Scriptorama » Afhankelijke listboxes met PHP, MySQLi en Prototype op 03.28.06 @ 10:50 pm | Permalink
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>