對於百萬行以上的 CSV,逐行 INSERT 效能極差(網絡往返、解析開銷、事務日誌)。MySQL 原生 LOAD DATA INFILE 直接由服務端讀取文件、解析、批量寫入,**速度快 10-100 倍**,且佔用極少 PHP 記憶體。
<?php
// 資料庫配置
$host = '192.168.1.10';
$user = 'root';
$pass = '11111';
$db = 'csvimport';
$pdo = new PDO("mysql:host={$host};dbname={$db};charset=utf8mb4", $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
// CSV 文件路徑(必須為 MySQL 服務端可訪問的絕對路徑)
$csvFile = '/root/bill20120813121249.csv';
// 構建 SQL
$sql = <<exec($sql);
echo "導入成功,影響行數:{$pdo->exec('SELECT ROW_COUNT()')}";
} catch (PDOException $e) {
die("導入失敗:" . $e->getMessage());
}
?>
| 子句 | 含義 | 常見值 |
|---|---|---|
FIELDS TERMINATED BY | 欄位分隔符 | ','、'\t'、';' |
ENCLOSED BY | 欄位包圍字符(可選) | '"'"、"'" |
ESCAPED BY | 轉義字符 | '"'"、'\\' |
LINES TERMINATED BY | 行結束符 | '\n' (Linux)、'\r\n' (Windows)、'\r' (舊 Mac) |
IGNORE 1 LINES | 跳過前 N 行(通常為標題行) | IGNORE 1 LINES |
SET col = expr | 導入時轉換/賦值(如日期格式化) | SET created_at = STR_TO_DATE(@var, '%Y-%m-%d') |
FILE 權限:GRANT FILE ON *.* TO 'user'@'host';secure_file_priv 限制:secure_file_priv,限制導入文件目錄。查看:SHOW VARIABLES LIKE 'secure_file_priv';NULL → 禁用導入/var/lib/mysql-files/ → 文件必須放在此目錄下my.cnf 重啟服務。LOAD DATA LOCAL INFILE,需雙端開啟 local_infile=1,PDO 連接參數加入 PDO::MYSQL_ATTR_LOCAL_INFILE => true。LOAD DATA INFILE '/path/file.csv'
INTO TABLE `orders`
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(@order_no, @raw_date, @amount, @status)
SET
`order_no` = TRIM(@order_no),
`order_date` = STR_TO_DATE(@raw_date, '%Y/%m/%d'),
`amount` = CAST(REPLACE(@amount, ',', '') AS DECIMAL(10,2)),
`status` = CASE TRIM(@status) WHEN 'paid' THEN 1 ELSE 0 END;
利用用戶變數 @var 接收原始列,再在 SET 中用 MySQL 函數清洗,避免 PHP 端逐行處理。
| 方式 | 耗時 | PHP 記憶體 | 備註 |
|---|---|---|---|
| PDO 逐行 prepare + execute | ~45 分鐘 | 低 | 網絡交互開銷大 |
| PDO 批次 INSERT (1000 行/批) | ~3 分鐘 | 中 | SQL 語句過長需調整 max_allowed_packet |
| LOAD DATA INFILE (本地) | ~8 秒 | 極低 | 最快,需文件在 DB 端 |
| LOAD DATA LOCAL INFILE | ~12 秒 | 低 | 跨機房網絡傳輸為瓶頸 |
ERROR 29 (HY000): File not found → 路徑錯誤、權限不足、secure_file_priv 限制ERROR 1265 (01000): Data truncated for column → 列長度不足、編碼不匹配、數值超出範圍ERROR 1300 (HY000): Invalid utf8mb4 character string → CSV 實際編碼非 UTF-8,需先 iconv -f gbk -t utf8mb4 file.csv > file_utf8.csvLINES TERMINATED BY 是否匹配文件實際換行符(用 hexdump -C file.csv | head 查看)LOAD DATA INFILE 是 MySQL 導入大量結構化數據的「核武器」。掌握其參數、權限、編碼、清洗技巧,能將原本小時級的導入任務壓縮至秒級。生產環境建議結合定時任務、臨時表、驗證邏輯構建穩健的 ETL 流程。