「到底是讀文件快還是查數據庫快?」這是無數 PHP 開發者心中的疑問。本文通過 10 萬次並發實測,從 4K 文本、整型 ID 兩個維度,對比 file_get_contents、fopen/fread 與 MySQL fetch_row/array/object 的真實性能表現,並給出生產環境架構選型建議。
| 項目 | 配置 |
|---|---|
| PHP 版本 | 5.3+ (CLI 模式) |
| MySQL | 5.1+ InnoDB, 唯一索引 log_ID |
| 測試數據 | 4K 文本內容 / 整型 ID |
| 迭代次數 | 100,000 次 |
| 文件讀取 | 連續兩次 fnGetContent() 模擬 DB 雙查詢 |
// 數據庫查詢基準
$begin = microtime(true);
for ($i = 0; $i < $times; $i++) {
$res = $dbcon->query("SELECT log_Content FROM blog WHERE log_ID='1'");
$row = $res->fetch_row(); // 或 fetch_array / fetch_object
$content = $row[0];
}
echo 'fetch_row ' . $times . ' 次耗時: ' . (microtime(true) - $begin) . '秒';
// 文件讀取基準
fnWriteCache('test.txt', $content); // 預熱寫入
$begin = microtime(true);
for ($i = 0; $i < $times; $i++) {
$content = file_get_contents('test.txt');
}
echo 'file_get_contents ' . $times . ' 次耗時: ' . (microtime(true) - $begin) . '秒';
| 方式 | 耗時 (秒) | 相對性能 |
|---|---|---|
| MySQL fetch_row | 16.74 | 1.00x (基準) |
| MySQL fetch_array | 16.66 | 1.00x |
| MySQL fetch_object | 16.78 | 1.00x |
| file_get_contents | 5.46 | 3.07x 更快 |
| fopen/fread | 11.46 | 1.46x |
| 方式 | 耗時 (秒) | 相對性能 |
|---|---|---|
| MySQL fetch_row | 12.81 | 1.00x |
| MySQL fetch_array | 12.67 | 1.01x |
| MySQL fetch_object | 12.99 | 0.99x |
| file_get_contents | 5.66 | 2.26x 更快 |
| fopen/fread | 11.54 | 1.11x |
文件讀取路徑:用戶態 → VFS → 文件系統 → 磁盤 (順序讀)
數據庫查詢路徑:用戶態 → PHP MySQL驅動 → TCP/Unix Socket → MySQL Server
→ 查詢解析 → 優化器 → 存儲引擎 → 緩存/磁盤 → 返回網絡 → 驅動解析 → PHP變量
即使數據最終都在磁盤,數據庫增加了 **網絡協議、SQL 解析、權限檢查、緩存管理** 等十餘層開銷。
4K 文本讀取比整型只快 ~30%,但 MySQL 耗時增長 ~30%。說明 MySQL 對大字段有額外處理(如溢出頁、協議分包),而文件系統順序讀受簇大小影響極小。
file_get_contents 內部使用內存映射 (mmap) 或優化流讀取,避免了用戶態多次 fread 系統調用。實測快 **2.1 倍**。
違背傳統認知。實際上 fetch_row 和 fetch_object 都是在 fetch_array 基礎上轉換而來,增加了數組→數值索引/對象映射開銷。
未測試但可推演:file_put_contents($file, $data, FILE_APPEND | LOCK_EX) 單次系統調用 vs INSERT 解析+事務+索引維護+WAL+刷盤,差距更懸殊。
| 場景 | 推薦方案 | 核心理由 |
|---|---|---|
| 配置文件、靜態模板、語言包 | PHP 數組文件 / .ini / JSON 文件 | 無查詢需求,OPcache 直接加載到內存,極快 |
| 用戶上傳圖片/視頻/文檔 | 對象存儲 (S3/OSS) + 數據庫存 URL | Blob 入庫災難性擴展,文件系統/對象存儲天生適配 |
| 高頻緩存(Session、Token、熱點數據) | Redis / Memcached | 內存級延遲,原子操作,TTL 自動過期 |
| 結構化業務數據、關聯查詢、事務一致性 | MySQL / PostgreSQL | ACID、SQL 靈活查詢、成熟生態,性能換正確性 |
| 日誌、審計、時序數據 | 文件追加 / ClickHouse / Elasticsearch | 順寫極快,壓縮率高,不需要隨機讀 |
| 單機高併發計數器 | 文件 flock + fwrite 或 Redis INCR | 避免數據庫行鎖熱點 |
opcache.preload 直接常駐內存「性能測試的意義不在於『誰更快』,而在於『邊界在哪裡』——在正確的邊界內做正確的選擇。」