首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

大數據 CSV 導入實戰:分批處理、超時突破與 SplFileObject 高效讀取

     編輯:PHP 相關知識

項目背景與挑戰

需導入約 5 萬條、5MB 的 CSV 數據。初期嘗試「上傳 → 讀取 → 入庫」一體化流程,卻接連踩坑:上傳等待體驗差、AJAX 請求 1 分鐘超時、單條插入性能低、continue 導致莫名 500 錯誤。

核心問題與解決方案

1. 上傳與處理解耦,優化用戶體驗

  • 先上傳文件到 import/ 目錄,返回文件名。
  • 前端收到文件名後提示「上傳成功」,再發起 AJAX 請求後端分批處理。

2. 突破 60 秒執行時間限制

排查過程:

  • 修改 max_execution_time = 300 無效
  • 嘗試 ini_set('max_input_time', 300),ini_get 仍返回 60
  • 修改 php.ini 重啟 Apache 後仍超時

根因: 可能受 Web 服務器(Apache/Nginx)或代理層的 Timeout/proxy_read_timeout 限制。

終極方案 —— 分批異步處理:

  • 每次 AJAX 請求處理 2000 行
  • 返回 {status: 'continue', processed: 2000}
  • 前端遞歸調用直到 status === 'done'

3. 去重邏輯中的 continue 陷阱

循環中使用 continue 跳過已存在記錄時,約在 8000 條報「Internal Server Error」。改用 if-else 結構後問題消失。推測與 GC 或內存峰值有關,具體原因待深究。

4. 批量插入提升性能

-- 慢:逐條執行
INSERT INTO t (a,b) VALUES (1,2);
INSERT INTO t (a,b) VALUES (3,4);

-- 快:單語句多值
INSERT INTO t (a,b) VALUES (1,2), (3,4), ...;

核心工具:SplFileObject 分行讀取

SplFileObject 內建指針控制,適合大文件隨機讀取,無需一次性載入內存。

function getFileLines($filename, $startLine, $endLine, $method = 'rb') {
    $content = [];
    $filename = DATA_PATH . DS . 'import' . DS . $filename;
    $count = $endLine - $startLine;
    $fp = new SplFileObject($filename, $method);
    $fp->seek($startLine); // 從 0 開始計數
    for ($i = 0; $i <= $count; ++$i) {
        $content[] = $fp->current();
        $fp->next();
    }
    return array_filter($content); // 過濾空行
}

經驗總結

  1. 大文件必須分批,避免單請求超時與內存溢出。
  2. 批量 SQL 是數據入庫性能的關鍵。
  3. SplFileObject 比 fgetcsv 更靈活,支持 seek() 隨機訪問。
  4. 遇到 continue 異常,優先嘗試 if-else 重構。

若您知道 continue 導致 500 錯誤的深層原因,或有更優雅的超時突破方案,歡迎留言交流!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved