クエリは、デフォルトではバッファモードで実行されます。 つまり、クエリの結果がすぐに MySQL サーバーから PHP に転送され、 PHP プロセスのメモリ内に結果を保持し続けるということです。 これで、その後で行数を数えたり結果ポインタを移動 (シーク) したりといった操作ができるようになります。 また、同じ接続上でさらに別のクエリを発行しつつ、 現在の結果セットを使った作業をすることもできます。 バッファモードの弱点は、結果セットが大きくなると大量にメモリを消費するということです。 結果セットへの参照がなくなるか、結果セットを明示的に解放する (リクエストを終了すると、自動的に解放されます) まではメモリ上に残り続けます。 バッファモードは「結果を格納する」クエリとも呼ばれます。 ここでは、結果セット全体が一度に格納されます。
注意:
ライブラリとして libmysqlclient を使っている場合は、結果セットのデータを PHP の変数に代入するまで結果セットのメモリ利用量が PHP のメモリ制限にカウントされません。 mysqlnd の場合は、結果セットのメモリがすべて PHP のメモリ制限にもカウントされます。
非バッファクエリは、クエリを実行してリソースを返しますが、 その時点ではまだデータが MySQL サーバー上にあって取得待ちになっています。 PHP 側でのメモリ消費が少なくなりますが、サーバーへの負荷は高くなります。 サーバー上の結果セットからすべての結果を取得するまで、 同じ接続上で別のクエリを実行することはできません。 非バッファクエリは「結果を使う」クエリとも呼ばれます。
こういった特性を考慮すると、バッファクエリを使うのは、 結果セットの量が限られている場合や事前に結果の行数を知りたい場合だけにとどめるべきでしょう。 結果が大量に返ってくることが想定できる場合は、非バッファモードを使わないといけません。
デフォルトはバッファモードなので、以下の例では それぞれの API で非バッファクエリを実行する方法を示します。
例1 非バッファクエリの例: mysqli
<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
$uresult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);
if ($uresult) {
while ($row = $uresult->fetch_assoc()) {
echo $row['Name'] . PHP_EOL;
}
}
?>
例2 非バッファクエリの例: pdo_mysql
<?php
$pdo = new PDO("mysql:host=localhost;dbname=world", 'my_user', 'my_pass');
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$uresult = $pdo->query("SELECT Name FROM City");
if ($uresult) {
while ($row = $uresult->fetch(PDO::FETCH_ASSOC)) {
echo $row['Name'] . PHP_EOL;
}
}
?>