PHPCon Poland 2024

Буферизированные и небуферизированные запросы

По умолчанию запросы используют режим буферизации. Это значит, что результаты запроса немедленно поступают от сервера MySQL к PHP и сохраняются в памяти PHP-процесса. Это позволяет делать дополнительные операции, такие как подсчёт количества строк и перемещение (поиск) текущего указателя результата. Это также даёт возможность выполнять новые запросы в том же соединении во время работы над результатом последнего запроса. Недостаток режима буферизации является то, что большие наборы результатов могут потребовать довольно много количество оперативной памяти. Память остаётся занятой до тех пор, пока все указатели на результирующий набор не будут удалены или результирующий набор не будет явно освобождён, что автоматически происходит во время окончания последнего запроса. Термин "результат сохранения" ("store result") также используется для режима буферизации, так как весь результирующий набор сохраняется сразу.

Замечание:

При использовании libmysqlclient в качестве библиотеки ограничение памяти PHP не будет учитывать память используемую для результирующих наборов, если данные не будут сохранены в переменные PHP. С mysqlnd учёт памяти также будет включать в себя размер результирующего набора.

Небуферизованные MySQL запросы выполняются, а затем ожидают получения данных с сервера MySQL. Это использует меньше памяти на стороне PHP, но может увеличить нагрузку на сервер. Пока полный результирующий набор не будет передан с сервера, никакие дальнейшие запросы не могут быть отправлены через это же соединение. Небуферизированные запросы также могут быть отложены как "use result". Когда все строки из набора результатов извлечены, набор результатов исчезает и его нельзя повторно итерировать.

Исходя из этих характеристик, небуферизированные запросы следует использовать только в тех случаях, когда ожидается большой набор результатов, который будет обрабатываться последовательно. Небуферизованные запросы содержат ряд подводных камней, что усложняет их использование, например, количество строк в наборе результатов неизвестно до тех пор, пока не будет извлечена последняя строка. Буферизованные запросы - более простой и гибкий способ обработки наборов результатов.

Поскольку буферизированные запросы применяются по умолчанию, следующие примеры продемонстрируют как выполнить небуферизированные запросы в каждом из API

Пример #1 Пример небуферизированного запроса: 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;
}
?>

Пример #2 Пример небуферизированного запроса: 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