mysql_query / PDO::query 預設採用緩衝模式:一次性將整個結果集載入 PHP 記憶體。查詢千萬級資料表時,極易觸發 Allowed memory size exhausted 致命錯誤。
MySQL 提供 mysql_unbuffered_query,PDO 對應 PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false。特點:
rowCount() 獲取總行數。function selecttest() {
$pdo = new PDO("mysql:host=localhost;dbname=test", 'root', '123456');
// $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); // 註釋=緩衝
$sth = $pdo->prepare('SELECT * FROM test');
$sth->execute();
echo '初始記憶體:' . memory_get_usage() . "\n";
$i = 0;
while ($result = $sth->fetch(PDO::FETCH_ASSOC)) {
$i++; if ($i > 10) break;
sleep(1);
print_r($result);
echo '當前記憶體:' . memory_get_usage() . "\n";
}
}
結果:執行 $sth->execute() 瞬間記憶體飆升,直接 OOM:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 204800000 bytes) ... on line 57
取消註釋 $pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
初始記憶體:144808 Array ( [id] => 1 [a] => v [b] => w [c] => i ) 當前記憶體:145544 Array ( [id] => 2 [a] => b [b] => l [c] => q ) 當前記憶體:145544 ... 記憶體穩定在 145KB 左右,極低且恆定
| 場景 | 建議模式 |
|---|---|
| 大量資料匯出、ETL、報表生成 | 無緩衝 |
| 需要預知總行數、分頁查詢 | 緩衝或另行 COUNT(*) |
| 同一連線交互多條 SQL | 緩衝或多連線 |
mysql_unbuffered_query() 在 PHP 5.5+ 棄用,7.0+ 移除。請全面遷移至 PDO 或 mysqli,PDO 範例:
$pdo = new PDO($dsn, $user, $pass, [
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false, // 關鍵
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->query('SELECT * FROM huge_table');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// 處理單行
}