核心差異對比
| 特性 | MYSQLI_STORE_RESULT (預設) | MYSQLI_USE_RESULT |
| 資料傳輸 | 查詢執行後立即將**所有結果集**傳輸到客戶端記憶體 | 查詢執行後**不傳輸資料**,需逐行呼叫 fetch 時才從伺服器讀取 |
| 記憶體佔用 | 高(客戶端緩衝整個結果集) | 低(僅緩衝當前行) |
| 伺服器負載 | 低(釋放伺服器資源快) | 高(伺服器需維持結果集直到讀完) |
| fetch 速度 | 極快(從本地記憶體讀取) | 較慢(每次需網路往返) |
| 錯誤檢測 | fetch 失敗只會在結束時返回 null | fetch 過程中可能發生網路錯誤 |
| 適用場景 | 小~中型結果集、需多次遍歷、隨機存取 | 大型結果集、串流處理、記憶體受限 |
程式碼示範
緩衝模式 (預設)
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$result = $mysqli->query('SELECT * FROM large_table'); // 預設 STORE_RESULT
// 此時所有資料已在客戶端記憶體
echo "總筆數: " . $result->num_rows; // 立即可用
while ($row = $result->fetch_assoc()) {
// 從本地記憶體讀取,極快
process($row);
}
$result->free(); // 釋放客戶端記憶體
非緩衝模式
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
$result = $mysqli->query('SELECT * FROM huge_table', MYSQLI_USE_RESULT);
// 無法立即取得 num_rows
// $result->num_rows 會報錯或返回 0
while ($row = $result->fetch_assoc()) {
// 每次從伺服器讀取一行
process($row);
// 可在處理中決定提前中斷,節省頻寬
if (shouldStop()) break;
}
// 若中斷讀取,需確保讀完或關閉連線釋放伺服器資源
實務決策指南
function chooseMode($estimatedRows, $avgRowSizeBytes, $memoryLimitMB = 128) {
$estimatedMemory = $estimatedRows * $avgRowSizeBytes;
$memoryLimit = $memoryLimitMB * 1024 * 1024 * 0.7; // 留 30% 給其他
if ($estimatedMemory < $memoryLimit) {
return MYSQLI_STORE_RESULT; // 安全,效能佳
}
return MYSQLI_USE_RESULT; // 節省記憶體
}
// 使用範例
$mode = chooseMode(100000, 500); // 10萬筆,平均500 bytes ≈ 50MB
$result = $mysqli->query($sql, $mode);
進階:分批處理大量資料
function processInChunks($mysqli, $sql, $chunkSize = 1000) {
$offset = 0;
do {
$chunkSql = "$sql LIMIT $offset, $chunkSize";
$result = $mysqli->query($chunkSql, MYSQLI_STORE_RESULT);
$count = 0;
while ($row = $result->fetch_assoc()) {
process($row);
$count++;
}
$result->free();
$offset += $chunkSize;
} while ($count === $chunkSize);
}
常見誤區
- 誤以為 USE_RESULT 更快:單行 fetch 確實較慢,但避免了大量記憶體分配,整體視情況而定
- USE_RESULT 時使用 num_rows:會導致錯誤,必須改用
SELECT COUNT(*) 另行查詢
- 未釋放結果集:STORE_RESULT 必須呼叫
free(),USE_RESULT 需讀完或關閉連線
- 在 USE_RESULT 期間執行其他查詢:會導致「Commands out of sync」錯誤