PHP Conference Japan 2024

緩衝與非緩衝查詢

預設情況下,查詢使用緩衝模式。這表示查詢結果會立即從 MySQL 伺服器傳輸到 PHP,然後保存在 PHP 程序的記憶體中。這允許額外的操作,例如計算列數和移動(搜尋)目前的結果指標。它還允許在處理結果集的同時,在同一個連線上發出進一步的查詢。緩衝模式的缺點是較大的結果集可能需要相當多的記憶體。記憶體將一直被佔用,直到所有對結果集的引用都被取消設定,或者結果集被明確釋放,這最遲會在請求結束時自動發生。「儲存結果」這一術語也用於緩衝模式,因為整個結果集是一次性儲存的。

注意:

當使用 libmysqlclient 作為程式庫時,PHP 的記憶體限制不會計算用於結果集的記憶體,除非資料被擷取到 PHP 變數中。使用 mysqlnd 時,計算的記憶體將包含完整的結果集。

非緩衝 MySQL 查詢會執行查詢,然後等待從 MySQL 伺服器擷取資料。這在 PHP 端使用較少的記憶體,但可能會增加伺服器的負載。除非從伺服器擷取了完整的結果集,否則無法通過同一個連線發送更多查詢。非緩衝查詢也可以稱為「使用結果」。一旦結果集中的所有列都被擷取,結果集就會消失,並且無法再次迭代。

根據這些特性,只有在預期會循序處理大型結果集時,才應該使用非緩衝查詢。非緩衝查詢包含許多陷阱,使其更難使用,例如,在擷取到最後一行之前,結果集中的列數是未知的。緩衝查詢是處理結果集更簡單、更靈活的方式。

由於緩衝查詢是預設設定,以下範例將演示如何使用每個 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;
}
?>
新增註解

使用者貢獻的註解 1 則註解

polygon dot co dot in at gmail dot com
1 年前
緩衝和非緩衝查詢可用於有限數量的記錄。

例如:使用緩衝方式實作 CSV 下載查詢時,超過 30,000 筆要緩衝的記錄時,就會出現記憶體限制問題。

同樣地,對於非緩衝查詢,負載會轉移到資料庫伺服器。

可以透過以下方式減少 Web 伺服器(緩衝)和 MySQL 伺服器(非緩衝)上的負載,以支援 30,000 筆以上記錄的 CSV 下載。

<?php
// Shell 命令。
$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 標頭
header("Content-type: text/csv");
header("Content-Disposition: attachment; filename={$csvFilename}");
header("Pragma: no-cache");
header("Expires: 0");

// 透過 shell 執行命令並以字串形式輸出完整結果
echo shell_exec($shellCommand);
?>

sed 正則表達式會消耗一些 CPU 資源。
To Top