PHPCon Poland 2024

Gepufferte und ungepufferte Abfragen

Abfragen werden standardmäßig im gepufferten Modus ausgeführt. Das bedeutet, dass die Abfrageergebnisse sofort vom MySQL-Server an PHP übertragen werden und dann im Speicher des PHP-Prozesses gehalten werden. Dies ermöglicht weitere Aktionen wie die Anzahl der Zeilen zu zählen und den aktuellen Ergebniszeiger zu verschieben (zu suchen). Außerdem ist es möglich, weitere Abfragen über dieselbe Verbindung durchzuführen, während die Ergebnismenge verarbeitet wird. Der Nachteil des gepufferten Modus ist, dass größere Ergebnismengen viel Speicherplatz benötigen können. Der Speicher bleibt so lange belegt, bis alle Verweise auf die Ergebnismenge aufgehoben sind oder die Ergebnismenge explizit freigegeben wurde, was spätestens beim Beenden der Abfrage automatisch geschieht. Weil beim gepufferten Modus die gesamte Ergebnismenge auf einmal gespeichert wird, wird auch der Ausdruck "store result" (Ergebnis speichern) verwendet.

Hinweis:

Wenn die Bibliothek libmysqlclient verwendet wird, wird der für eine Ergebnismenge verwendete Speicher nicht zum PHP-Speicherlimit gezählt, es sei denn, die Daten werden in PHP-Variablen abgerufen. Mit mysqlnd wird die gesamte Ergebnismenge in den Speicher mit eingerechnet.

Ungepufferte MySQL-Abfragen führen die Abfrage aus und warten dann darauf, dass die Daten vom MySQL-Server abgerufen werden. Dadurch wird zwar weniger Speicher von PHP verwendet, aber die Last auf dem Server kann steigen. Solange nicht die gesamte Ergebnismenge vom Server abgerufen wurde, können keine weiteren Abfragen über dieselbe Verbindung gesendet werden. Ungepufferte Abfragen können auch als "use result" (Ergebnis verwenden) bezeichnet werden. Nachdem alle Zeilen der Ergebnismenge abgerufen wurden, ist die Ergebnismenge weg, und kann nicht mehr durchlaufen werden.

Aufgrund dieser Merkmale sollten ungepufferte Abfragen nur verwendet werden, wenn eine große Ergebnismenge erwartet wird, die sequentiell verarbeitet werden soll. Ungepufferte Abfragen weisen eine Reihe von Fallstricken auf, die ihre Verwendung erschweren, z. B. ist die Anzahl der Zeilen in der Ergebnismenge erst bekannt, nachdem die letzte Zeile abgerufen wurde. Gepufferte Abfragen sind die einfachere und flexiblere Lösung, um Ergebnismengen zu verarbeiten.

Da standardmäßig gepufferte Abfragen verwendet werden, zeigen die folgenden Beispiele, wie ungepufferte Abfragen mit der jeweiligen API ausgeführt werden.

Beispiel #1 Beispiel für ungepufferte Abfragen: mysqli

<?php
$mysqli
= new mysqli("localhost", "my_user", "my_password", "world");
$unbufferedResult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);

foreach (
$unbufferedResult as $row) {
echo
$row['Name'] . PHP_EOL;
}
?>

Beispiel #2 Beispiel für ungepufferte Abfragen: pdo_mysql

<?php
$pdo
= new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_password');
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$unbufferedResult = $pdo->query("SELECT Name FROM City");
foreach (
$unbufferedResult as $row) {
echo
$row['Name'] . PHP_EOL;
}
?>
add a note

User Contributed Notes 1 note

up
0
polygon dot co dot in at gmail dot com
10 months ago
The bufferred and unbuffered queries can be used for a limited amount of records.

For example; while implementing download CSV for a query using buffered way, memory limit issues comes up above 30,000 records to be buffered.

Similarly, For unbuffered the load switched to database server.

This load on both the web (buffered) and MySQL (unbuffered) servers can be reduced as below supporting download CSV for 30,000+ records.

<?php
// Shell command.
$shellCommand = 'mysql '
. '--host='.escapeshellarg($hostname).' '
. '--user='.escapeshellarg($username).' '
. '--password='.escapeshellarg($password).' '
. '--database='.escapeshellarg($database).' '
. '--execute='.escapeshellarg($sql).' '
. '| sed -e \'s/"/""/g ; s/\t/","/g ; s/^/"/g ; s/$/"/g\'';

// CSV headers
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename={$csvFilename}");
header("Pragma: no-cache");
header("Expires: 0");

// Execute command via shell and echo the complete output as a string
echo shell_exec($shellCommand);
?>

There will be a bit of CPU consumption for the sed regex.
To Top