PHP 舊版 mysql_* 擴展(已棄用,僅供維護舊專案參考)提供四種獲取結果集方法。本文對比其效能、回傳結構、適用場景,並給出現代 PDO/MySQLi 的對應最佳實踐。
| 方法 | 回傳結構 | 效能排名 | 特點 | 適用場景 |
|---|---|---|---|---|
mysql_result() | 單一標量值 | 最慢 (1x 基準) | 隨機存取任意行/欄,每次呼叫內部 seek | 極少量資料、特定單值提取 |
mysql_fetch_row() | 數值索引陣列 [0,1,2] | 最快 (~1.2x) | 僅數值索引,記憶體最省 | 高效能、不需欄位名、固定欄位順序 |
mysql_fetch_array() | 雙模式 [0=>val, 'col'=>val] | 快 (~1.25x) | 預設 MYSQL_BOTH,可指定 MYSQL_NUM/MYSQL_ASSOC | 最常用,兼顧可讀性與效能 |
mysql_fetch_object() | 物件 $row->col | 較慢 (~1.4x) | 面向物件風格,屬性名=欄位名 | OOP 專案、結構複雜、需封裝邏輯 |
$link = mysql_connect('localhost', 'root', 'root');
mysql_select_db('test');
mysql_query('SET NAMES utf8');
$sql = "SELECT * FROM large_table LIMIT 100000";
$res = mysql_query($sql);
// 1. mysql_result
$start = microtime(true);
while ($row = mysql_fetch_row($res)) { /* ... */ }
echo "fetch_row: " . (microtime(true) - $start);
// 2. mysql_fetch_array
mysql_data_seek($res, 0);
$start = microtime(true);
while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) { /* ... */ }
echo "fetch_array: " . (microtime(true) - $start);
// 3. mysql_fetch_object
mysql_data_seek($res, 0);
$start = microtime(true);
while ($row = mysql_fetch_object($res)) { /* ... */ }
echo "fetch_object: " . (microtime(true) - $start);
mysql_* 擴展自 PHP 7.0 移除,新專案必須使用 PDO 或 MySQLi。
| mysql_* 方法 | PDO 對應 | MySQLi 對應 |
|---|---|---|
| mysql_fetch_row() | PDO::FETCH_NUM | mysqli_fetch_row() |
| mysql_fetch_array(MYSQL_ASSOC) | PDO::FETCH_ASSOC | mysqli_fetch_assoc() |
| mysql_fetch_array(MYSQL_BOTH) | PDO::FETCH_BOTH (預設) | mysqli_fetch_array(MYSQLI_BOTH) |
| mysql_fetch_object() | PDO::FETCH_OBJ / FETCH_CLASS | mysqli_fetch_object() |
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // 預設關聯陣列
PDO::ATTR_EMULATE_PREPARES => false,
]);
$stmt = $pdo->query("SELECT id, name, email FROM users LIMIT 100000");
foreach ($stmt as $row) {
// $row = ['id'=>1, 'name'=>'John', 'email'=>'john@example.com']
// 直接用欄位名存取,可讀性最佳
process($row['name'], $row['email']);
}
// 大資料集分批處理 (生成器模式)
function fetchBatch(PDO $pdo, string $sql, int $batch = 1000): Generator {
$stmt = $pdo->query($sql);
$batchData = [];
foreach ($stmt as $row) {
$batchData[] = $row;
if (count($batchData) >= $batch) {
yield $batchData;
$batchData = [];
}
}
if ($batchData) yield $batchData;
}
foreach (fetchBatch($pdo, "SELECT * FROM logs") as $batch) {
processBatch($batch); // 記憶體穩定
}
PDO::FETCH_NUM / mysqli_fetch_row(),搭配生成器分批。PDO::FETCH_CLASS 映射到 Entity 類別,或 FETCH_OBJ。方法選擇不應只看微基準測試,而應以代碼可維護性、安全性、記憶體穩定性為首要考量。PDO::FETCH_ASSOC 是 95% 場景的最優解。