執行大量資料查詢時,PHP 拋出致命錯誤:
PHP Fatal error: Allowed memory size of 268435456 bytes exhausted
根本原因:PHP 預設使用緩衝查詢,將整個結果集一次性載入記憶體,導致記憶體用盡。
| 特性 | 緩衝查詢 | 非緩衝查詢 |
|---|---|---|
| 資料傳輸 | 一次性從 MySQL 取回所有列到 PHP 記憶體 | MySQL 伺服器逐列傳送,PHP 逐列處理 |
| 記憶體佔用 | 高(正比於結果集大小) | 極低(僅保留當前列) |
| 功能支援 | 可計算行數、移動指標、重複遍歷 | 僅單向單次遍歷,不可回頭 |
| 伺服器負載 | 查詢結束即釋放資源 | 查詢期間持續佔用連線與執行緒 |
| 適用場景 | 小型結果集、需隨機存取 | 大型結果集、串流處理、匯出報表 |
<?php
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");
// 關鍵:傳入 MYSQLI_USE_RESULT 常數啟用非緩衝模式
$uresult = $mysqli->query("SELECT Name FROM City", MYSQLI_USE_RESULT);
if ($uresult) {
while ($row = $uresult->fetch_assoc()) {
echo $row['Name'] . PHP_EOL; // 逐列處理
}
$uresult->close(); // 必須釋放結果集,否則後續查詢會失敗
}
?>
<?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;
}
}
?>
<?php
$conn = mysql_connect("localhost", "my_user", "my_pass");
mysql_select_db("world");
// 關鍵:使用 mysql_unbuffered_query 而非 mysql_query
$uresult = mysql_unbuffered_query("SELECT Name FROM City");
if ($uresult) {
while ($row = mysql_fetch_assoc($uresult)) {
echo $row['Name'] . PHP_EOL;
}
}
?>
<?php
$pdo = new PDO("mysql:host=localhost;dbname=world", 'user', 'pass');
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->query("SELECT id, data FROM huge_table");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// 處理單筆資料:寫入檔案、發送 API、計算統計...
processRow($row);
}
// 記憶體佔用恆定,不隨資料量增長
?>
function fetchRows(PDO $pdo, string $sql): Generator {
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->query($sql);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield $row;
}
}
foreach (fetchRows($pdo, "SELECT * FROM huge_table") as $row) {
// 記憶體高效處理
}
SELECT *,僅選取必要欄位,減少網路傳輸與記憶體佔用。LIMIT offset, size 深分頁效能差;大量資料優先用非緩衝游標或 WHERE id > last_id 方式。wait_timeout/max_execution_time。掌握緩衝與非緩衝查詢的差異與適用場景,配合 Generator 等現代 PHP 特性,即可優雅解決大量資料查詢的記憶體耗盡問題。